Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add requested limits to static meta #34361

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}