use one definition of builtin program cost in runtime and banking stage (#31930)

* use one definition of builtin program cost in runtime and banking stage
* add loader_v4
This commit is contained in:
Tao Zhu 2023-06-02 10:22:22 -05:00 committed by GitHub
parent e587df1285
commit 10995f66c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1016 additions and 950 deletions

View File

@ -18,7 +18,12 @@ use {
std::convert::TryFrom, std::convert::TryFrom,
}; };
declare_process_instruction!(process_instruction, 750, |invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data(); let instruction_data = instruction_context.get_instruction_data();
@ -36,7 +41,8 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
} }
ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context), ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context),
} }
}); }
);
fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> { fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> {
a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow) a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow)

View File

@ -62,6 +62,10 @@ use {
syscalls::create_program_runtime_environment, syscalls::create_program_runtime_environment,
}; };
pub const DEFAULT_LOADER_COMPUTE_UNITS: u64 = 570;
pub const DEPRECATED_LOADER_COMPUTE_UNITS: u64 = 1_140;
pub const UPGRADEABLE_LOADER_COMPUTE_UNITS: u64 = 2_370;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn load_program_from_bytes( pub fn load_program_from_bytes(
feature_set: &FeatureSet, feature_set: &FeatureSet,
@ -515,17 +519,17 @@ fn process_instruction_inner(
let program_id = instruction_context.get_last_program_key(transaction_context)?; let program_id = instruction_context.get_last_program_key(transaction_context)?;
return if bpf_loader_upgradeable::check_id(program_id) { return if bpf_loader_upgradeable::check_id(program_id) {
if native_programs_consume_cu { if native_programs_consume_cu {
invoke_context.consume_checked(2_370)?; invoke_context.consume_checked(UPGRADEABLE_LOADER_COMPUTE_UNITS)?;
} }
process_loader_upgradeable_instruction(invoke_context) process_loader_upgradeable_instruction(invoke_context)
} else if bpf_loader::check_id(program_id) { } else if bpf_loader::check_id(program_id) {
if native_programs_consume_cu { if native_programs_consume_cu {
invoke_context.consume_checked(570)?; invoke_context.consume_checked(DEFAULT_LOADER_COMPUTE_UNITS)?;
} }
process_loader_instruction(invoke_context) process_loader_instruction(invoke_context)
} else if bpf_loader_deprecated::check_id(program_id) { } else if bpf_loader_deprecated::check_id(program_id) {
if native_programs_consume_cu { if native_programs_consume_cu {
invoke_context.consume_checked(1_140)?; invoke_context.consume_checked(DEPRECATED_LOADER_COMPUTE_UNITS)?;
} }
ic_logger_msg!(log_collector, "Deprecated loader is no longer supported"); ic_logger_msg!(log_collector, "Deprecated loader is no longer supported");
Err(InstructionError::UnsupportedProgramId) Err(InstructionError::UnsupportedProgramId)

View File

@ -1,6 +1,12 @@
use solana_program_runtime::declare_process_instruction; use solana_program_runtime::declare_process_instruction;
declare_process_instruction!(process_instruction, 150, |_invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|_invoke_context| {
// Do nothing, compute budget instructions handled by the runtime // Do nothing, compute budget instructions handled by the runtime
Ok(()) Ok(())
}); }
);

View File

@ -11,7 +11,12 @@ use {
std::collections::BTreeSet, std::collections::BTreeSet,
}; };
declare_process_instruction!(process_instruction, 450, |invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 450;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data(); let data = instruction_context.get_instruction_data();
@ -131,7 +136,8 @@ declare_process_instruction!(process_instruction, 450, |invoke_context| {
} }
config_account.get_data_mut()?[..data.len()].copy_from_slice(data); config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
Ok(()) Ok(())
}); }
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -38,6 +38,8 @@ use {
}, },
}; };
pub const DEFAULT_COMPUTE_UNITS: u64 = 2_000;
pub fn get_state(data: &[u8]) -> Result<&LoaderV4State, InstructionError> { pub fn get_state(data: &[u8]) -> Result<&LoaderV4State, InstructionError> {
unsafe { unsafe {
let data = data let data = data
@ -560,7 +562,7 @@ pub fn process_instruction_inner(
.feature_set .feature_set
.is_active(&feature_set::native_programs_consume_cu::id()) .is_active(&feature_set::native_programs_consume_cu::id())
{ {
invoke_context.consume_checked(2000)?; invoke_context.consume_checked(DEFAULT_COMPUTE_UNITS)?;
} }
match limited_deserialize(instruction_data)? { match limited_deserialize(instruction_data)? {
LoaderV4Instruction::Write { offset, bytes } => { LoaderV4Instruction::Write { offset, bytes } => {

View File

@ -51,7 +51,12 @@ fn get_optional_pubkey<'a>(
) )
} }
declare_process_instruction!(process_instruction, 750, |invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data(); let data = instruction_context.get_instruction_data();
@ -70,7 +75,8 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
match limited_deserialize(data) { match limited_deserialize(data) {
Ok(StakeInstruction::Initialize(authorized, lockup)) => { Ok(StakeInstruction::Initialize(authorized, lockup)) => {
let mut me = get_stake_account()?; let mut me = get_stake_account()?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; let rent =
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
initialize( initialize(
&mut me, &mut me,
&authorized, &authorized,
@ -86,8 +92,11 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
if require_custodian_for_locked_stake_authorize { if require_custodian_for_locked_stake_authorize {
let clock = let clock = get_sysvar_with_account_check::clock(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; invoke_context,
instruction_context,
1,
)?;
instruction_context.check_number_of_instruction_accounts(3)?; instruction_context.check_number_of_instruction_accounts(3)?;
let custodian_pubkey = let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 3, false)?; get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
@ -120,8 +129,11 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
.feature_set .feature_set
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
if require_custodian_for_locked_stake_authorize { if require_custodian_for_locked_stake_authorize {
let clock = let clock = get_sysvar_with_account_check::clock(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; invoke_context,
instruction_context,
2,
)?;
let custodian_pubkey = let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 3, false)?; get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
@ -171,7 +183,8 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
if !config::check_id(config_account.get_key()) { if !config::check_id(config_account.get_key()) {
return Err(InstructionError::InvalidArgument); return Err(InstructionError::InvalidArgument);
} }
let config = config::from(&config_account).ok_or(InstructionError::InvalidArgument)?; let config =
config::from(&config_account).ok_or(InstructionError::InvalidArgument)?;
drop(config_account); drop(config_account);
delegate( delegate(
invoke_context, invoke_context,
@ -284,8 +297,11 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
withdrawer: *withdrawer_pubkey, withdrawer: *withdrawer_pubkey,
}; };
let rent = let rent = get_sysvar_with_account_check::rent(
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; invoke_context,
instruction_context,
1,
)?;
initialize( initialize(
&mut me, &mut me,
&authorized, &authorized,
@ -303,8 +319,11 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
.feature_set .feature_set
.is_active(&feature_set::vote_stake_checked_instructions::id()) .is_active(&feature_set::vote_stake_checked_instructions::id())
{ {
let clock = let clock = get_sysvar_with_account_check::clock(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; invoke_context,
instruction_context,
1,
)?;
instruction_context.check_number_of_instruction_accounts(4)?; instruction_context.check_number_of_instruction_accounts(4)?;
let authorized_pubkey = transaction_context.get_key_of_account_at_index( let authorized_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(3)?, instruction_context.get_index_of_instruction_account_in_transaction(3)?,
@ -335,8 +354,11 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
.is_active(&feature_set::vote_stake_checked_instructions::id()) .is_active(&feature_set::vote_stake_checked_instructions::id())
{ {
instruction_context.check_number_of_instruction_accounts(2)?; instruction_context.check_number_of_instruction_accounts(2)?;
let clock = let clock = get_sysvar_with_account_check::clock(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; invoke_context,
instruction_context,
2,
)?;
instruction_context.check_number_of_instruction_accounts(4)?; instruction_context.check_number_of_instruction_accounts(4)?;
let authorized_pubkey = transaction_context.get_key_of_account_at_index( let authorized_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(3)?, instruction_context.get_index_of_instruction_account_in_transaction(3)?,
@ -429,8 +451,8 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
.is_active(&feature_set::stake_redelegate_instruction::id()) .is_active(&feature_set::stake_redelegate_instruction::id())
{ {
instruction_context.check_number_of_instruction_accounts(3)?; instruction_context.check_number_of_instruction_accounts(3)?;
let config_account = let config_account = instruction_context
instruction_context.try_borrow_instruction_account(transaction_context, 3)?; .try_borrow_instruction_account(transaction_context, 3)?;
if !config::check_id(config_account.get_key()) { if !config::check_id(config_account.get_key()) {
return Err(InstructionError::InvalidArgument); return Err(InstructionError::InvalidArgument);
} }
@ -475,7 +497,8 @@ declare_process_instruction!(process_instruction, 750, |invoke_context| {
Err(err) Err(err)
} }
} }
}); }
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -312,7 +312,12 @@ fn transfer_with_seed(
) )
} }
declare_process_instruction!(process_instruction, 150, |invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data(); let instruction_data = instruction_context.get_instruction_data();
@ -445,7 +450,8 @@ declare_process_instruction!(process_instruction, 150, |invoke_context| {
instruction_context, instruction_context,
2, 2,
)?; )?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?; let rent =
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
withdraw_nonce_account( withdraw_nonce_account(
0, 0,
lamports, lamports,
@ -474,7 +480,8 @@ declare_process_instruction!(process_instruction, 150, |invoke_context| {
); );
return Err(SystemError::NonceNoRecentBlockhashes.into()); return Err(SystemError::NonceNoRecentBlockhashes.into());
} }
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?; let rent =
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
initialize_nonce_account(&mut me, &authorized, &rent, invoke_context) initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
} }
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
@ -551,7 +558,8 @@ declare_process_instruction!(process_instruction, 150, |invoke_context| {
assign(&mut account, &address, &owner, &signers, invoke_context) assign(&mut account, &address, &owner, &signers, invoke_context)
} }
} }
}); }
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -52,7 +52,12 @@ fn process_authorize_with_seed_instruction(
// Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2100 // Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2100
// units; can consume based on instructions in the future like `bpf_loader` does. // units; can consume based on instructions in the future like `bpf_loader` does.
declare_process_instruction!(process_instruction, 2100, |invoke_context| { pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data(); let data = instruction_context.get_instruction_data();
@ -67,7 +72,8 @@ declare_process_instruction!(process_instruction, 2100, |invoke_context| {
let signers = instruction_context.get_signers(transaction_context)?; let signers = instruction_context.get_signers(transaction_context)?;
match limited_deserialize(data)? { match limited_deserialize(data)? {
VoteInstruction::InitializeAccount(vote_init) => { VoteInstruction::InitializeAccount(vote_init) => {
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; let rent =
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
if !rent.is_exempt(me.get_lamports(), me.get_data().len()) { if !rent.is_exempt(me.get_lamports(), me.get_data().len()) {
return Err(InstructionError::InsufficientFunds); return Err(InstructionError::InsufficientFunds);
} }
@ -156,8 +162,11 @@ declare_process_instruction!(process_instruction, 2100, |invoke_context| {
) )
} }
VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => {
let slot_hashes = let slot_hashes = get_sysvar_with_account_check::slot_hashes(
get_sysvar_with_account_check::slot_hashes(invoke_context, instruction_context, 1)?; invoke_context,
instruction_context,
1,
)?;
let clock = let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
vote_state::process_vote_with_account( vote_state::process_vote_with_account(
@ -245,8 +254,11 @@ declare_process_instruction!(process_instruction, 2100, |invoke_context| {
if !instruction_context.is_instruction_account_signer(3)? { if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
let clock = let clock = get_sysvar_with_account_check::clock(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; invoke_context,
instruction_context,
1,
)?;
vote_state::authorize( vote_state::authorize(
&mut me, &mut me,
voter_pubkey, voter_pubkey,
@ -260,7 +272,8 @@ declare_process_instruction!(process_instruction, 2100, |invoke_context| {
} }
} }
} }
}); }
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -4,7 +4,7 @@ use {
lazy_static::lazy_static, lazy_static::lazy_static,
solana_sdk::{ solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, compute_budget, ed25519_program, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, compute_budget, ed25519_program,
feature, incinerator, native_loader, pubkey::Pubkey, secp256k1_program, system_program, loader_v4, pubkey::Pubkey, secp256k1_program,
}, },
std::collections::HashMap, std::collections::HashMap,
}; };
@ -32,21 +32,19 @@ pub const INSTRUCTION_DATA_BYTES_COST: u64 = 140 /*bytes per us*/ / COMPUTE_UNIT
lazy_static! { lazy_static! {
/// Number of compute units for each built-in programs /// Number of compute units for each built-in programs
pub static ref BUILT_IN_INSTRUCTION_COSTS: HashMap<Pubkey, u64> = [ pub static ref BUILT_IN_INSTRUCTION_COSTS: HashMap<Pubkey, u64> = [
(feature::id(), COMPUTE_UNIT_TO_US_RATIO * 2), (solana_stake_program::id(), solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS),
(incinerator::id(), COMPUTE_UNIT_TO_US_RATIO * 2), (solana_config_program::id(), solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS),
(native_loader::id(), COMPUTE_UNIT_TO_US_RATIO * 2), (solana_vote_program::id(), solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS),
(solana_sdk::stake::config::id(), COMPUTE_UNIT_TO_US_RATIO * 2), (solana_system_program::id(), solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS),
(solana_sdk::stake::program::id(), COMPUTE_UNIT_TO_US_RATIO * 25), (compute_budget::id(), solana_compute_budget_program::DEFAULT_COMPUTE_UNITS),
(solana_config_program::id(), COMPUTE_UNIT_TO_US_RATIO * 15), (solana_address_lookup_table_program::id(), solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS),
(solana_vote_program::id(), COMPUTE_UNIT_TO_US_RATIO * 70), (bpf_loader_upgradeable::id(), solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS),
(bpf_loader_deprecated::id(), solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS),
(bpf_loader::id(), solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS),
(loader_v4::id(), solana_loader_v4_program::DEFAULT_COMPUTE_UNITS),
// Note: These are precompile, run directly in bank during sanitizing;
(secp256k1_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24), (secp256k1_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
(ed25519_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24), (ed25519_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
(system_program::id(), COMPUTE_UNIT_TO_US_RATIO * 5),
(compute_budget::id(), COMPUTE_UNIT_TO_US_RATIO * 5),
(solana_address_lookup_table_program::id(), COMPUTE_UNIT_TO_US_RATIO * 25),
(bpf_loader_upgradeable::id(), COMPUTE_UNIT_TO_US_RATIO * 79),
(bpf_loader_deprecated::id(), COMPUTE_UNIT_TO_US_RATIO * 38),
(bpf_loader::id(), COMPUTE_UNIT_TO_US_RATIO * 19),
] ]
.iter() .iter()
.cloned() .cloned()