diff --git a/src/account_size_class.rs b/src/account_size_class.rs new file mode 100644 index 00000000..8b774476 --- /dev/null +++ b/src/account_size_class.rs @@ -0,0 +1,75 @@ +const KB: u32 = 1024; +const MB: u32 = 1024 * KB; + +// +// PERFORMANCE TIP: if a single transaction contains N dlp-instructions, add +// DLP_PROGRAM_DATA_SIZE_CLASS once, not N times. So consider doing something like this: +// +// let size_budget = commit_diff_size_budget(blah) +// + finalize_size_budget(blah) +// + undelegate_size_budget(blah) +// - 2 * DLP_PROGRAM_DATA_SIZE_CLASS.size_budget(); +// +// That is because each *_size_budget() function includes this constant, so callers must subtract (N-1) instances +// when combining multiple instructions. +// +pub const DLP_PROGRAM_DATA_SIZE_CLASS: AccountSizeClass = AccountSizeClass::Dynamic(350 * KB); + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum AccountSizeClass { + // account size <= 256 B + // + // - sysvars (rent, clock, epoch schedule) + // - SPL token account and ATA + // - SPL token mint + // - delegation_metadata_pda + // - delegation_record_pda + // - commit_record_pda + // - program_config_pda + // - validator + // - fees_vault_pda + Tiny, + + // account size <= 1 KB + // + // - sysvars (recent blockhash) + Small, + + // account size <= 8 KB + // + // - sysvars (instructions) + Medium, + + // account size <= 64 KB + // + // - sysvars (state history) + Large, + + // account size <= 256 KB + // + ExtraLarge, + + // account size <= 1 MB + Huge, + + // any legal value + Dynamic(u32), +} + +impl AccountSizeClass { + pub const fn size_budget(self) -> u32 { + match self { + Self::Tiny => 256, + Self::Small => KB, + Self::Medium => 8 * KB, + Self::Large => 64 * KB, + Self::ExtraLarge => 256 * KB, + Self::Huge => MB, + Self::Dynamic(n) => n, + } + } +} + +pub fn total_size_budget(classes: &[AccountSizeClass]) -> u32 { + classes.iter().map(|f| f.size_budget()).sum() +} diff --git a/src/instruction_builder/call_handler.rs b/src/instruction_builder/call_handler.rs index 6f895486..81cffd1c 100644 --- a/src/instruction_builder/call_handler.rs +++ b/src/instruction_builder/call_handler.rs @@ -1,6 +1,7 @@ use crate::args::CallHandlerArgs; use crate::discriminator::DlpDiscriminator; use crate::pda::{ephemeral_balance_pda_from_payer, validator_fees_vault_pda_from_validator}; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; use borsh::to_vec; use solana_program::instruction::Instruction; use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; @@ -38,3 +39,19 @@ pub fn call_handler( .concat(), } } + +/// +/// Returns accounts-data-size budget for call_handler instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn call_handler_size_budget(destination_program: AccountSizeClass, other_accounts: u32) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + AccountSizeClass::Tiny, // validator_fees_vault_pda + destination_program, + AccountSizeClass::Tiny, // escrow_authority + AccountSizeClass::Tiny, // escrow_account + ]) + other_accounts +} diff --git a/src/instruction_builder/commit_diff.rs b/src/instruction_builder/commit_diff.rs index 5ef87de4..b770c43e 100644 --- a/src/instruction_builder/commit_diff.rs +++ b/src/instruction_builder/commit_diff.rs @@ -10,6 +10,7 @@ use crate::pda::{ delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, program_config_from_program_id, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a commit state instruction. /// See [crate::processor::fast::process_commit_diff] for docs. @@ -43,3 +44,23 @@ pub fn commit_diff( data: [DlpDiscriminator::CommitDiff.to_vec(), commit_args].concat(), } } + +/// +/// Returns accounts-data-size budget for commit_diff instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn commit_diff_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // program_config_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/commit_diff_from_buffer.rs b/src/instruction_builder/commit_diff_from_buffer.rs index f1913dbf..5349d8e9 100644 --- a/src/instruction_builder/commit_diff_from_buffer.rs +++ b/src/instruction_builder/commit_diff_from_buffer.rs @@ -10,6 +10,7 @@ use crate::pda::{ delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, program_config_from_program_id, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a commit state from buffer instruction. /// See [crate::processor::process_commit_diff_from_buffer] for docs. @@ -45,3 +46,24 @@ pub fn commit_diff_from_buffer( data: [DlpDiscriminator::CommitDiffFromBuffer.to_vec(), commit_args].concat(), } } + +/// +/// Returns accounts-data-size budget for commit_diff_from_buffer instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn commit_diff_from_buffer_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + delegated_account, // commit_state_buffer + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // program_config_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/commit_state.rs b/src/instruction_builder/commit_state.rs index b6f5ce0e..8ac476d1 100644 --- a/src/instruction_builder/commit_state.rs +++ b/src/instruction_builder/commit_state.rs @@ -10,6 +10,7 @@ use crate::pda::{ delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, program_config_from_program_id, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a commit state instruction. /// See [crate::processor::process_commit_state] for docs. @@ -43,3 +44,23 @@ pub fn commit_state( data: [DlpDiscriminator::CommitState.to_vec(), commit_args].concat(), } } + +/// +/// Returns accounts-data-size budget for commit_state instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn commit_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // program_config_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/commit_state_from_buffer.rs b/src/instruction_builder/commit_state_from_buffer.rs index dc932305..a16c7a2a 100644 --- a/src/instruction_builder/commit_state_from_buffer.rs +++ b/src/instruction_builder/commit_state_from_buffer.rs @@ -10,6 +10,7 @@ use crate::pda::{ delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, program_config_from_program_id, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a commit state from buffer instruction. /// See [crate::processor::process_commit_state_from_buffer] for docs. @@ -49,3 +50,24 @@ pub fn commit_state_from_buffer( .concat(), } } + +/// +/// Returns accounts-data-size budget for commit_state_from_buffer instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn commit_state_from_buffer_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + delegated_account, // commit_state_buffer + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // program_config_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/delegate.rs b/src/instruction_builder/delegate.rs index d89c5069..83030ef6 100644 --- a/src/instruction_builder/delegate.rs +++ b/src/instruction_builder/delegate.rs @@ -9,6 +9,7 @@ use crate::pda::{ delegate_buffer_pda_from_delegated_account_and_owner_program, delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a delegate instruction /// See [crate::processor::process_delegate] for docs. @@ -41,3 +42,21 @@ pub fn delegate( data, } } + +/// +/// Returns accounts-data-size budget for delegate instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn delegate_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // payer + delegated_account, // delegated_account + AccountSizeClass::Tiny, // owner + delegated_account, // delegate_buffer_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/finalize.rs b/src/instruction_builder/finalize.rs index 38226dd2..c70a5a97 100644 --- a/src/instruction_builder/finalize.rs +++ b/src/instruction_builder/finalize.rs @@ -8,6 +8,7 @@ use crate::pda::{ delegation_metadata_pda_from_delegated_account, delegation_record_pda_from_delegated_account, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds a finalize state instruction. /// See [crate::processor::process_finalize] for docs. @@ -33,3 +34,22 @@ pub fn finalize(validator: Pubkey, delegated_account: Pubkey) -> Instruction { data: DlpDiscriminator::Finalize.to_vec(), } } + +/// +/// Returns accounts-data-size budget for finalize instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn finalize_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/instruction_builder/undelegate.rs b/src/instruction_builder/undelegate.rs index 54c1b80b..c576c053 100644 --- a/src/instruction_builder/undelegate.rs +++ b/src/instruction_builder/undelegate.rs @@ -9,6 +9,7 @@ use crate::pda::{ fees_vault_pda, undelegate_buffer_pda_from_delegated_account, validator_fees_vault_pda_from_validator, }; +use crate::{total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS}; /// Builds an undelegate instruction. /// See [crate::processor::process_undelegate] for docs. @@ -46,3 +47,26 @@ pub fn undelegate( data: DlpDiscriminator::Undelegate.to_vec(), } } + +/// +/// Returns accounts-data-size budget for undelegate instruction. +/// +/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit +/// +pub fn undelegate_size_budget(delegated_account: AccountSizeClass) -> u32 { + total_size_budget(&[ + DLP_PROGRAM_DATA_SIZE_CLASS, + AccountSizeClass::Tiny, // validator + delegated_account, // delegated_account + AccountSizeClass::Tiny, // owner_program + delegated_account, // undelegate_buffer_pda + delegated_account, // commit_state_pda + AccountSizeClass::Tiny, // commit_record_pda + AccountSizeClass::Tiny, // delegation_record_pda + AccountSizeClass::Tiny, // delegation_metadata_pda + AccountSizeClass::Tiny, // rent_reimbursement + AccountSizeClass::Tiny, // fees_vault_pda + AccountSizeClass::Tiny, // validator_fees_vault_pda + AccountSizeClass::Tiny, // system_program + ]) +} diff --git a/src/lib.rs b/src/lib.rs index 9a405ec0..44a4cc93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,10 @@ pub mod instruction_builder; pub mod pda; pub mod state; +mod account_size_class; + +pub use account_size_class::*; + #[cfg(not(feature = "sdk"))] mod diff; #[cfg(not(feature = "sdk"))]