diff --git a/runtime-transaction/src/runtime_transaction.rs b/runtime-transaction/src/runtime_transaction.rs index df6acbccdd2905..1c48ce399aa352 100644 --- a/runtime-transaction/src/runtime_transaction.rs +++ b/runtime-transaction/src/runtime_transaction.rs @@ -10,12 +10,14 @@ //! ALT, RuntimeTransaction transits into Dynamically Loaded state, //! with its dynamic metadata loaded. use { - crate::transaction_meta::{DynamicMeta, StaticMeta, TransactionMeta}, + crate::transaction_meta::{DynamicMeta, RequestedLimits, StaticMeta, TransactionMeta}, + solana_program_runtime::compute_budget_processor::ComputeBudgetLimits, solana_sdk::{ hash::Hash, message::{AddressLoader, SanitizedMessage, SanitizedVersionedMessage}, signature::Signature, simple_vote_transaction_checker::is_simple_vote_transaction, + slot_history::Slot, transaction::{Result, SanitizedVersionedTransaction}, }, }; @@ -41,6 +43,17 @@ impl StaticMetaAccess for SanitizedVersionedMessage {} impl StaticMetaAccess for SanitizedMessage {} impl DynamicMetaAccess for SanitizedMessage {} +impl RequestedLimits for RuntimeTransaction { + fn requested_limits(&self, current_slot: Option) -> Option<&ComputeBudgetLimits> { + if let Some(current_slot) = current_slot { + (current_slot <= self.meta.requested_limits.expiry) + .then(|| &self.meta.requested_limits.compute_budget_limits) + } else { + Some(&self.meta.requested_limits.compute_budget_limits) + } + } +} + impl StaticMeta for RuntimeTransaction { fn message_hash(&self) -> &Hash { &self.meta.message_hash @@ -48,6 +61,18 @@ impl StaticMeta for RuntimeTransaction { fn is_simple_vote_tx(&self) -> bool { self.meta.is_simple_vote_tx } + fn compute_unit_limit(&self, current_slot: Option) -> Option { + self.requested_limits(current_slot) + .and_then(|requested_limits| Some(requested_limits.compute_unit_limit)) + } + fn compute_unit_price(&self, current_slot: Option) -> Option { + self.requested_limits(current_slot) + .and_then(|requested_limits| Some(requested_limits.compute_unit_price)) + } + fn loaded_accounts_bytes(&self, current_slot: Option) -> Option { + self.requested_limits(current_slot) + .and_then(|requested_limits| Some(requested_limits.loaded_accounts_bytes)) + } } impl DynamicMeta for RuntimeTransaction {} @@ -103,6 +128,7 @@ impl RuntimeTransaction { mod tests { use { super::*, + crate::transaction_meta::RequestedLimitsWithExpiry, solana_program::{ system_instruction, vote::{self, state::Vote}, @@ -162,11 +188,13 @@ mod tests { fn test_new_runtime_transaction_static() { let hash = Hash::new_unique(); let compute_unit_price = 1_000; + let requested_limits = RequestedLimitsWithExpiry::default(); assert_eq!( TransactionMeta { message_hash: hash, is_simple_vote_tx: false, + requested_limits: requested_limits.clone(), }, get_transaction_meta( non_vote_sanitized_versioned_transaction(compute_unit_price), @@ -179,6 +207,7 @@ mod tests { TransactionMeta { message_hash: hash, is_simple_vote_tx: true, + requested_limits: requested_limits.clone(), }, get_transaction_meta( non_vote_sanitized_versioned_transaction(compute_unit_price), @@ -191,6 +220,7 @@ mod tests { TransactionMeta { message_hash: hash, is_simple_vote_tx: true, + requested_limits: requested_limits.clone(), }, get_transaction_meta(vote_sanitized_versioned_transaction(), Some(hash), None) ); @@ -199,6 +229,7 @@ mod tests { TransactionMeta { message_hash: hash, is_simple_vote_tx: false, + requested_limits, }, get_transaction_meta( vote_sanitized_versioned_transaction(), diff --git a/runtime-transaction/src/transaction_meta.rs b/runtime-transaction/src/transaction_meta.rs index 2eec699f291e36..c01ba3817142bf 100644 --- a/runtime-transaction/src/transaction_meta.rs +++ b/runtime-transaction/src/transaction_meta.rs @@ -11,13 +11,29 @@ //! The StaticMeta and DynamicMeta traits are accessor traits on the //! RuntimeTransaction types, not the TransactionMeta itself. //! -use solana_sdk::hash::Hash; +use { + solana_program_runtime::compute_budget_processor::ComputeBudgetLimits, + solana_sdk::{hash::Hash, slot_history::Slot}, +}; + +/// private trait to avoid exposing `ComputeBudgetLimits` to callsite of RuntimeTransaction. +pub(crate) trait RequestedLimits { + fn requested_limits(&self, current_slot: Option) -> Option<&ComputeBudgetLimits>; +} /// metadata can be extracted statically from sanitized transaction, -/// for example: message hash, simple-vote-tx flag, compute budget limits, -pub trait StaticMeta { +/// for example: message hash, simple-vote-tx flag, limits set by instructions +#[allow(private_bounds)] +pub trait StaticMeta: RequestedLimits { fn message_hash(&self) -> &Hash; fn is_simple_vote_tx(&self) -> bool; + + // get fields' value from RequestedLimitsWithExpiry, + // `current_slot`, sets to None to skip expiry check, otherwise if current_slot is + // before expiry, Some(value) is returned, otherwise return None. + fn compute_unit_limit(&self, current_slot: Option) -> Option; + fn compute_unit_price(&self, current_slot: Option) -> Option; + fn loaded_accounts_bytes(&self, current_slot: Option) -> Option; } /// Statically loaded meta is a supertrait of Dynamically loaded meta, when @@ -31,6 +47,16 @@ pub trait DynamicMeta: StaticMeta {} pub struct TransactionMeta { pub(crate) message_hash: Hash, pub(crate) is_simple_vote_tx: bool, + pub(crate) requested_limits: RequestedLimitsWithExpiry, +} + +/// Processing compute_budget_instructions with feature_set resolves RequestedLimits, +/// and the resolved values expire at the end of the current epoch, as feature_set +/// may change between epochs. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub(crate) struct RequestedLimitsWithExpiry { + pub(crate) expiry: Slot, + pub(crate) compute_budget_limits: ComputeBudgetLimits, } impl TransactionMeta {