Skip to content

Commit

Permalink
add requested limits to static meta (#34361)
Browse files Browse the repository at this point in the history
* add requested limits to static meta
* rebase to catch up on compue_budget_processor no longer needs feature_set; update requested limits as flat fields of static meta without expiry
  • Loading branch information
tao-stones authored Dec 16, 2023
1 parent 5a5561f commit 0168321
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 69 deletions.
200 changes: 132 additions & 68 deletions runtime-transaction/src/runtime_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
//! with its dynamic metadata loaded.
use {
crate::transaction_meta::{DynamicMeta, StaticMeta, TransactionMeta},
solana_program_runtime::compute_budget_processor::{
process_compute_budget_instructions, ComputeBudgetLimits,
},
solana_sdk::{
hash::Hash,
message::{AddressLoader, SanitizedMessage, SanitizedVersionedMessage},
Expand Down Expand Up @@ -48,6 +51,15 @@ impl<M: StaticMetaAccess> StaticMeta for RuntimeTransaction<M> {
fn is_simple_vote_tx(&self) -> bool {
self.meta.is_simple_vote_tx
}
fn compute_unit_limit(&self) -> u32 {
self.meta.compute_unit_limit
}
fn compute_unit_price(&self) -> u64 {
self.meta.compute_unit_price
}
fn loaded_accounts_bytes(&self) -> u32 {
self.meta.loaded_accounts_bytes
}
}

impl<M: DynamicMetaAccess> DynamicMeta for RuntimeTransaction<M> {}
Expand All @@ -65,9 +77,18 @@ impl RuntimeTransaction<SanitizedVersionedMessage> {
);

let (signatures, message) = sanitized_versioned_tx.destruct();

meta.set_message_hash(message_hash.unwrap_or_else(|| message.message.hash()));

let ComputeBudgetLimits {
compute_unit_limit,
compute_unit_price,
loaded_accounts_bytes,
..
} = process_compute_budget_instructions(message.program_instructions_iter())?;
meta.set_compute_unit_limit(compute_unit_limit);
meta.set_compute_unit_price(compute_unit_price);
meta.set_loaded_accounts_bytes(loaded_accounts_bytes);

Ok(Self {
signatures,
message,
Expand Down Expand Up @@ -109,6 +130,7 @@ mod tests {
},
solana_sdk::{
compute_budget::ComputeBudgetInstruction,
instruction::Instruction,
message::Message,
signer::{keypair::Keypair, Signer},
transaction::{SimpleAddressLoader, Transaction, VersionedTransaction},
Expand All @@ -131,91 +153,98 @@ mod tests {
SanitizedVersionedTransaction::try_from(VersionedTransaction::from(vote_tx)).unwrap()
}

fn non_vote_sanitized_versioned_transaction(
compute_unit_price: u64,
) -> SanitizedVersionedTransaction {
let from_keypair = Keypair::new();
let ixs = vec![
system_instruction::transfer(
fn non_vote_sanitized_versioned_transaction() -> SanitizedVersionedTransaction {
TestTransaction::new().to_sanitized_versioned_transaction()
}

// Simple transfer transaction for testing, it does not support vote instruction
// because simple vote transaction will not request limits
struct TestTransaction {
from_keypair: Keypair,
hash: Hash,
instructions: Vec<Instruction>,
}

impl TestTransaction {
fn new() -> Self {
let from_keypair = Keypair::new();
let instructions = vec![system_instruction::transfer(
&from_keypair.pubkey(),
&solana_sdk::pubkey::new_rand(),
1,
),
ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
];
let message = Message::new(&ixs, Some(&from_keypair.pubkey()));
let tx = Transaction::new(&[&from_keypair], message, Hash::new_unique());
SanitizedVersionedTransaction::try_from(VersionedTransaction::from(tx)).unwrap()
}
)];
TestTransaction {
from_keypair,
hash: Hash::new_unique(),
instructions,
}
}

fn get_transaction_meta(
svt: SanitizedVersionedTransaction,
hash: Option<Hash>,
is_simple_vote: Option<bool>,
) -> TransactionMeta {
RuntimeTransaction::<SanitizedVersionedMessage>::try_from(svt, hash, is_simple_vote)
.unwrap()
.meta
fn add_compute_unit_limit(&mut self, val: u32) -> &mut TestTransaction {
self.instructions
.push(ComputeBudgetInstruction::set_compute_unit_limit(val));
self
}

fn add_compute_unit_price(&mut self, val: u64) -> &mut TestTransaction {
self.instructions
.push(ComputeBudgetInstruction::set_compute_unit_price(val));
self
}

fn add_loaded_accounts_bytes(&mut self, val: u32) -> &mut TestTransaction {
self.instructions
.push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(val));
self
}

fn to_sanitized_versioned_transaction(&self) -> SanitizedVersionedTransaction {
let message = Message::new(&self.instructions, Some(&self.from_keypair.pubkey()));
let tx = Transaction::new(&[&self.from_keypair], message, self.hash);
SanitizedVersionedTransaction::try_from(VersionedTransaction::from(tx)).unwrap()
}
}

#[test]
fn test_new_runtime_transaction_static() {
let hash = Hash::new_unique();
let compute_unit_price = 1_000;
fn test_runtime_transaction_is_vote_meta() {
fn get_is_simple_vote(
svt: SanitizedVersionedTransaction,
is_simple_vote: Option<bool>,
) -> bool {
RuntimeTransaction::<SanitizedVersionedMessage>::try_from(svt, None, is_simple_vote)
.unwrap()
.meta
.is_simple_vote_tx
}

assert_eq!(
TransactionMeta {
message_hash: hash,
is_simple_vote_tx: false,
},
get_transaction_meta(
non_vote_sanitized_versioned_transaction(compute_unit_price),
Some(hash),
None
)
);
assert!(!get_is_simple_vote(
non_vote_sanitized_versioned_transaction(),
None
));

assert_eq!(
TransactionMeta {
message_hash: hash,
is_simple_vote_tx: true,
},
get_transaction_meta(
non_vote_sanitized_versioned_transaction(compute_unit_price),
Some(hash),
Some(true), // override
)
);
assert!(get_is_simple_vote(
non_vote_sanitized_versioned_transaction(),
Some(true), // override
));

assert_eq!(
TransactionMeta {
message_hash: hash,
is_simple_vote_tx: true,
},
get_transaction_meta(vote_sanitized_versioned_transaction(), Some(hash), None)
);
assert!(get_is_simple_vote(
vote_sanitized_versioned_transaction(),
None
));

assert_eq!(
TransactionMeta {
message_hash: hash,
is_simple_vote_tx: false,
},
get_transaction_meta(
vote_sanitized_versioned_transaction(),
Some(hash),
Some(false), // override
)
);
assert!(!get_is_simple_vote(
vote_sanitized_versioned_transaction(),
Some(false), // override
));
}

#[test]
fn test_advance_transaction_type() {
fn test_advancing_transaction_type() {
let hash = Hash::new_unique();
let compute_unit_price = 999;

let statically_loaded_transaction =
RuntimeTransaction::<SanitizedVersionedMessage>::try_from(
non_vote_sanitized_versioned_transaction(compute_unit_price),
non_vote_sanitized_versioned_transaction(),
Some(hash),
None,
)
Expand All @@ -234,4 +263,39 @@ mod tests {
assert_eq!(hash, *dynamically_loaded_transaction.message_hash());
assert!(!dynamically_loaded_transaction.is_simple_vote_tx());
}

#[test]
fn test_runtime_transaction_static_meta() {
let hash = Hash::new_unique();
let compute_unit_limit = 250_000;
let compute_unit_price = 1_000;
let loaded_accounts_bytes = 1_024;
let mut test_transaction = TestTransaction::new();

let runtime_transaction_static = RuntimeTransaction::<SanitizedVersionedMessage>::try_from(
test_transaction
.add_compute_unit_limit(compute_unit_limit)
.add_compute_unit_price(compute_unit_price)
.add_loaded_accounts_bytes(loaded_accounts_bytes)
.to_sanitized_versioned_transaction(),
Some(hash),
None,
)
.unwrap();

assert_eq!(&hash, runtime_transaction_static.message_hash());
assert!(!runtime_transaction_static.is_simple_vote_tx());
assert_eq!(
compute_unit_limit,
runtime_transaction_static.compute_unit_limit()
);
assert_eq!(
compute_unit_price,
runtime_transaction_static.compute_unit_price()
);
assert_eq!(
loaded_accounts_bytes,
runtime_transaction_static.loaded_accounts_bytes()
);
}
}
20 changes: 19 additions & 1 deletion runtime-transaction/src/transaction_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
use solana_sdk::hash::Hash;

/// metadata can be extracted statically from sanitized transaction,
/// for example: message hash, simple-vote-tx flag, compute budget limits,
/// for example: message hash, simple-vote-tx flag, limits set by instructions
pub trait StaticMeta {
fn message_hash(&self) -> &Hash;
fn is_simple_vote_tx(&self) -> bool;
fn compute_unit_limit(&self) -> u32;
fn compute_unit_price(&self) -> u64;
fn loaded_accounts_bytes(&self) -> u32;
}

/// Statically loaded meta is a supertrait of Dynamically loaded meta, when
Expand All @@ -31,6 +34,9 @@ pub trait DynamicMeta: StaticMeta {}
pub struct TransactionMeta {
pub(crate) message_hash: Hash,
pub(crate) is_simple_vote_tx: bool,
pub(crate) compute_unit_limit: u32,
pub(crate) compute_unit_price: u64,
pub(crate) loaded_accounts_bytes: u32,
}

impl TransactionMeta {
Expand All @@ -41,4 +47,16 @@ impl TransactionMeta {
pub(crate) fn set_is_simple_vote_tx(&mut self, is_simple_vote_tx: bool) {
self.is_simple_vote_tx = is_simple_vote_tx;
}

pub(crate) fn set_compute_unit_limit(&mut self, compute_unit_limit: u32) {
self.compute_unit_limit = compute_unit_limit;
}

pub(crate) fn set_compute_unit_price(&mut self, compute_unit_price: u64) {
self.compute_unit_price = compute_unit_price;
}

pub(crate) fn set_loaded_accounts_bytes(&mut self, loaded_accounts_bytes: u32) {
self.loaded_accounts_bytes = loaded_accounts_bytes;
}
}

0 comments on commit 0168321

Please sign in to comment.