Feature gate builtin consumes static units during processing instruction (#30702)
* add feature gate * builtins consume statically defined units at beginning of process_instruction() * Add new instructionError; return error if builtin did not consume units to enforce builtin to consume units; * updated related tests * updated ProgramTest with deactivated native_programs_consume_cu feature to continue support existing mock/test programs that do not consume units
This commit is contained in:
parent
5a05e9bacf
commit
3e500d9e92
|
@ -15,7 +15,10 @@ use {
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{AccountSharedData, ReadableAccount},
|
account::{AccountSharedData, ReadableAccount},
|
||||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||||
feature_set::{enable_early_verification_of_account_modifications, FeatureSet},
|
feature_set::{
|
||||||
|
enable_early_verification_of_account_modifications, native_programs_consume_cu,
|
||||||
|
FeatureSet,
|
||||||
|
},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, InstructionError},
|
instruction::{AccountMeta, InstructionError},
|
||||||
native_loader,
|
native_loader,
|
||||||
|
@ -751,8 +754,9 @@ impl<'a> InvokeContext<'a> {
|
||||||
self.transaction_context
|
self.transaction_context
|
||||||
.set_return_data(program_id, Vec::new())?;
|
.set_return_data(program_id, Vec::new())?;
|
||||||
|
|
||||||
|
let is_builtin_program = builtin_id == program_id;
|
||||||
let pre_remaining_units = self.get_remaining();
|
let pre_remaining_units = self.get_remaining();
|
||||||
let result = if builtin_id == program_id {
|
let result = if is_builtin_program {
|
||||||
let logger = self.get_log_collector();
|
let logger = self.get_log_collector();
|
||||||
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
||||||
(entry.process_instruction)(self)
|
(entry.process_instruction)(self)
|
||||||
|
@ -769,6 +773,15 @@ impl<'a> InvokeContext<'a> {
|
||||||
let post_remaining_units = self.get_remaining();
|
let post_remaining_units = self.get_remaining();
|
||||||
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
|
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
|
||||||
|
|
||||||
|
if is_builtin_program
|
||||||
|
&& *compute_units_consumed == 0
|
||||||
|
&& self
|
||||||
|
.feature_set
|
||||||
|
.is_active(&native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
return Err(InstructionError::BuiltinProgramsMustConsumeComputeUnits);
|
||||||
|
}
|
||||||
|
|
||||||
process_executable_chain_time.stop();
|
process_executable_chain_time.stop();
|
||||||
saturating_add_assign!(
|
saturating_add_assign!(
|
||||||
timings
|
timings
|
||||||
|
@ -1082,6 +1095,8 @@ mod tests {
|
||||||
assert!(!format!("{builtin_programs:?}").is_empty());
|
assert!(!format!("{builtin_programs:?}").is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MOCK_BUILTIN_COMPUTE_UNIT_COST: u64 = 1;
|
||||||
|
|
||||||
#[allow(clippy::integer_arithmetic)]
|
#[allow(clippy::integer_arithmetic)]
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
|
@ -1090,6 +1105,8 @@ mod tests {
|
||||||
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();
|
||||||
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(MOCK_BUILTIN_COMPUTE_UNIT_COST)?;
|
||||||
let instruction_accounts = (0..4)
|
let instruction_accounts = (0..4)
|
||||||
.map(|instruction_account_index| InstructionAccount {
|
.map(|instruction_account_index| InstructionAccount {
|
||||||
index_in_transaction: instruction_account_index,
|
index_in_transaction: instruction_account_index,
|
||||||
|
@ -1372,7 +1389,10 @@ mod tests {
|
||||||
// the number of compute units consumed should be a non-default which is something greater
|
// the number of compute units consumed should be a non-default which is something greater
|
||||||
// than zero.
|
// than zero.
|
||||||
assert!(compute_units_consumed > 0);
|
assert!(compute_units_consumed > 0);
|
||||||
assert_eq!(compute_units_consumed, compute_units_to_consume);
|
assert_eq!(
|
||||||
|
compute_units_consumed,
|
||||||
|
compute_units_to_consume + MOCK_BUILTIN_COMPUTE_UNIT_COST
|
||||||
|
);
|
||||||
assert_eq!(result, expected_result);
|
assert_eq!(result, expected_result);
|
||||||
|
|
||||||
invoke_context.pop().unwrap();
|
invoke_context.pop().unwrap();
|
||||||
|
|
|
@ -463,13 +463,18 @@ impl Default for ProgramTest {
|
||||||
let prefer_bpf =
|
let prefer_bpf =
|
||||||
std::env::var("BPF_OUT_DIR").is_ok() || std::env::var("SBF_OUT_DIR").is_ok();
|
std::env::var("BPF_OUT_DIR").is_ok() || std::env::var("SBF_OUT_DIR").is_ok();
|
||||||
|
|
||||||
|
// deactivate feature `native_program_consume_cu` to continue support existing mock/test
|
||||||
|
// programs that do not consume units.
|
||||||
|
let deactivate_feature_set =
|
||||||
|
HashSet::from([solana_sdk::feature_set::native_programs_consume_cu::id()]);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
accounts: vec![],
|
accounts: vec![],
|
||||||
builtins: vec![],
|
builtins: vec![],
|
||||||
compute_max_units: None,
|
compute_max_units: None,
|
||||||
prefer_bpf,
|
prefer_bpf,
|
||||||
use_bpf_jit: false,
|
use_bpf_jit: false,
|
||||||
deactivate_feature_set: HashSet::default(),
|
deactivate_feature_set,
|
||||||
transaction_account_lock_limit: None,
|
transaction_account_lock_limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(750)?;
|
||||||
|
}
|
||||||
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();
|
||||||
|
|
|
@ -45,8 +45,8 @@ use {
|
||||||
check_slice_translation_size, delay_visibility_of_program_deployment,
|
check_slice_translation_size, delay_visibility_of_program_deployment,
|
||||||
disable_deploy_of_alloc_free_syscall, enable_bpf_loader_extend_program_ix,
|
disable_deploy_of_alloc_free_syscall, enable_bpf_loader_extend_program_ix,
|
||||||
enable_bpf_loader_set_authority_checked_ix, enable_program_redeployment_cooldown,
|
enable_bpf_loader_set_authority_checked_ix, enable_program_redeployment_cooldown,
|
||||||
limit_max_instruction_trace_length, remove_bpf_loader_incorrect_program_id,
|
limit_max_instruction_trace_length, native_programs_consume_cu,
|
||||||
round_up_heap_size, FeatureSet,
|
remove_bpf_loader_incorrect_program_id, round_up_heap_size, FeatureSet,
|
||||||
},
|
},
|
||||||
instruction::{AccountMeta, InstructionError},
|
instruction::{AccountMeta, InstructionError},
|
||||||
loader_instruction::LoaderInstruction,
|
loader_instruction::LoaderInstruction,
|
||||||
|
@ -520,15 +520,29 @@ fn process_instruction_common(
|
||||||
let program_account =
|
let program_account =
|
||||||
instruction_context.try_borrow_last_program_account(transaction_context)?;
|
instruction_context.try_borrow_last_program_account(transaction_context)?;
|
||||||
|
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated
|
||||||
|
let native_programs_consume_cu = invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&native_programs_consume_cu::id());
|
||||||
|
|
||||||
// Program Management Instruction
|
// Program Management Instruction
|
||||||
if native_loader::check_id(program_account.get_owner()) {
|
if native_loader::check_id(program_account.get_owner()) {
|
||||||
drop(program_account);
|
drop(program_account);
|
||||||
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 {
|
||||||
|
invoke_context.consume_checked(2_370)?;
|
||||||
|
}
|
||||||
process_loader_upgradeable_instruction(invoke_context, use_jit)
|
process_loader_upgradeable_instruction(invoke_context, use_jit)
|
||||||
} else if bpf_loader::check_id(program_id) {
|
} else if bpf_loader::check_id(program_id) {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(570)?;
|
||||||
|
}
|
||||||
process_loader_instruction(invoke_context, use_jit)
|
process_loader_instruction(invoke_context, use_jit)
|
||||||
} else if bpf_loader_deprecated::check_id(program_id) {
|
} else if bpf_loader_deprecated::check_id(program_id) {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(1_140)?;
|
||||||
|
}
|
||||||
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)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
use {
|
use {
|
||||||
solana_program_runtime::invoke_context::InvokeContext,
|
solana_program_runtime::invoke_context::InvokeContext,
|
||||||
solana_sdk::instruction::InstructionError,
|
solana_sdk::{feature_set, instruction::InstructionError},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_instruction(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(150)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Do nothing, compute budget instructions handled by the runtime
|
// Do nothing, compute budget instructions handled by the runtime
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,14 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
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();
|
||||||
|
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(450)?;
|
||||||
|
}
|
||||||
|
|
||||||
let key_list: ConfigKeys = limited_deserialize(data)?;
|
let key_list: ConfigKeys = limited_deserialize(data)?;
|
||||||
let config_account_key = transaction_context.get_key_of_account_at_index(
|
let config_account_key = transaction_context.get_key_of_account_at_index(
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
|
|
|
@ -1470,7 +1470,7 @@ fn test_program_sbf_compute_budget() {
|
||||||
);
|
);
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
ComputeBudgetInstruction::set_compute_unit_limit(1),
|
ComputeBudgetInstruction::set_compute_unit_limit(150),
|
||||||
Instruction::new_with_bincode(program_id, &0, vec![]),
|
Instruction::new_with_bincode(program_id, &0, vec![]),
|
||||||
],
|
],
|
||||||
Some(&mint_keypair.pubkey()),
|
Some(&mint_keypair.pubkey()),
|
||||||
|
@ -2185,7 +2185,13 @@ fn test_program_sbf_disguised_as_sbf_loader() {
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
..
|
..
|
||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
|
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
// disable native_programs_consume_cu feature to allow test program
|
||||||
|
// not consume units.
|
||||||
|
let mut feature_set = FeatureSet::all_enabled();
|
||||||
|
feature_set.deactivate(&solana_sdk::feature_set::native_programs_consume_cu::id());
|
||||||
|
bank.feature_set = Arc::new(feature_set);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||||
bank.add_builtin(&name, &id, entrypoint);
|
bank.add_builtin(&name, &id, entrypoint);
|
||||||
bank.deactivate_feature(
|
bank.deactivate_feature(
|
||||||
|
|
|
@ -58,6 +58,14 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(750)?;
|
||||||
|
}
|
||||||
|
|
||||||
let get_stake_account = || {
|
let get_stake_account = || {
|
||||||
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
|
|
|
@ -62,6 +62,16 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
// Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2_100
|
||||||
|
// units; can consume based on instructions in the future like `bpf_loader` does.
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(2_100)?;
|
||||||
|
}
|
||||||
|
|
||||||
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
|
|
|
@ -4,6 +4,7 @@ use {
|
||||||
bytemuck::Pod,
|
bytemuck::Pod,
|
||||||
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
|
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
|
feature_set,
|
||||||
instruction::{InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT},
|
instruction::{InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT},
|
||||||
system_program,
|
system_program,
|
||||||
},
|
},
|
||||||
|
@ -119,12 +120,10 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
return Err(InstructionError::UnsupportedProgramId);
|
return Err(InstructionError::UnsupportedProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume compute units since proof verification is an expensive operation
|
// Consume compute units if feature `native_programs_consume_cu` is activated
|
||||||
{
|
let native_programs_consume_cu = invoke_context
|
||||||
// TODO: Tune the number of units consumed. The current value is just a rough estimate
|
.feature_set
|
||||||
invoke_context.consume_checked(100_000)?;
|
.is_active(&feature_set::native_programs_consume_cu::id());
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
||||||
|
@ -137,28 +136,46 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
process_close_proof_context(invoke_context)
|
process_close_proof_context(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyCloseAccount => {
|
ProofInstruction::VerifyCloseAccount => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(6_012)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyCloseAccount");
|
ic_msg!(invoke_context, "VerifyCloseAccount");
|
||||||
process_verify_proof::<CloseAccountData, CloseAccountProofContext>(invoke_context)
|
process_verify_proof::<CloseAccountData, CloseAccountProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyWithdraw => {
|
ProofInstruction::VerifyWithdraw => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(112_454)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyWithdraw");
|
ic_msg!(invoke_context, "VerifyWithdraw");
|
||||||
process_verify_proof::<WithdrawData, WithdrawProofContext>(invoke_context)
|
process_verify_proof::<WithdrawData, WithdrawProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyWithdrawWithheldTokens => {
|
ProofInstruction::VerifyWithdrawWithheldTokens => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(7_943)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyWithdrawWithheldTokens");
|
ic_msg!(invoke_context, "VerifyWithdrawWithheldTokens");
|
||||||
process_verify_proof::<WithdrawWithheldTokensData, WithdrawWithheldTokensProofContext>(
|
process_verify_proof::<WithdrawWithheldTokensData, WithdrawWithheldTokensProofContext>(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyTransfer => {
|
ProofInstruction::VerifyTransfer => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(219_290)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyTransfer");
|
ic_msg!(invoke_context, "VerifyTransfer");
|
||||||
process_verify_proof::<TransferData, TransferProofContext>(invoke_context)
|
process_verify_proof::<TransferData, TransferProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyTransferWithFee => {
|
ProofInstruction::VerifyTransferWithFee => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(407_121)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyTransferWithFee");
|
ic_msg!(invoke_context, "VerifyTransferWithFee");
|
||||||
process_verify_proof::<TransferWithFeeData, TransferWithFeeProofContext>(invoke_context)
|
process_verify_proof::<TransferWithFeeData, TransferWithFeeProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
ProofInstruction::VerifyPubkeyValidity => {
|
ProofInstruction::VerifyPubkeyValidity => {
|
||||||
|
if native_programs_consume_cu {
|
||||||
|
invoke_context.consume_checked(2_619)?;
|
||||||
|
}
|
||||||
ic_msg!(invoke_context, "VerifyPubkeyValidity");
|
ic_msg!(invoke_context, "VerifyPubkeyValidity");
|
||||||
process_verify_proof::<PubkeyValidityData, PubkeyValidityProofContext>(invoke_context)
|
process_verify_proof::<PubkeyValidityData, PubkeyValidityProofContext>(invoke_context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5890,7 +5890,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
"returnData":null,
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":150,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
@ -5974,7 +5974,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
"returnData":null,
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":150,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
@ -6002,7 +6002,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
"returnData":null,
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":150,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
@ -6051,7 +6051,7 @@ pub mod tests {
|
||||||
"accounts":null,
|
"accounts":null,
|
||||||
"logs":[],
|
"logs":[],
|
||||||
"returnData":null,
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id":1
|
"id":1
|
||||||
|
@ -6080,7 +6080,7 @@ pub mod tests {
|
||||||
"Program 11111111111111111111111111111111 success"
|
"Program 11111111111111111111111111111111 success"
|
||||||
],
|
],
|
||||||
"returnData":null,
|
"returnData":null,
|
||||||
"unitsConsumed":0
|
"unitsConsumed":150,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
|
|
@ -283,7 +283,7 @@ impl RentDebits {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BankStatusCache = StatusCache<Result<()>>;
|
pub type BankStatusCache = StatusCache<Result<()>>;
|
||||||
#[frozen_abi(digest = "3qia1Zm8X66bzFaBuC8ahz3hADRRATyUPRV36ZzrSois")]
|
#[frozen_abi(digest = "GBTLfFjModD9ykS9LV4pGi4S8eCrUj2JjWSDQLf8tMwV")]
|
||||||
pub type BankSlotDelta = SlotDelta<Result<()>>;
|
pub type BankSlotDelta = SlotDelta<Result<()>>;
|
||||||
|
|
||||||
// Eager rent collection repeats in cyclic manner.
|
// Eager rent collection repeats in cyclic manner.
|
||||||
|
|
|
@ -5129,8 +5129,10 @@ fn test_add_duplicate_static_program() {
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
fn mock_vote_processor(
|
fn mock_vote_processor(
|
||||||
_invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5177,8 +5179,10 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
|
||||||
let mut bank = create_simple_test_bank(500);
|
let mut bank = create_simple_test_bank(500);
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
_invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6473,6 +6477,8 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
|
||||||
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();
|
||||||
let lamports = u64::from_le_bytes(instruction_data.try_into().unwrap());
|
let lamports = u64::from_le_bytes(instruction_data.try_into().unwrap());
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
instruction_context
|
instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 2)?
|
.try_borrow_instruction_account(transaction_context, 2)?
|
||||||
.checked_sub_lamports(lamports)?;
|
.checked_sub_lamports(lamports)?;
|
||||||
|
@ -6526,8 +6532,10 @@ fn test_transaction_with_program_ids_passed_to_programs() {
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
_invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6744,8 +6752,10 @@ fn test_program_id_as_payer() {
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn mock_ok_vote_processor(
|
fn mock_ok_vote_processor(
|
||||||
_invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10193,6 +10203,8 @@ fn test_transfer_sysvar() {
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
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()?;
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
instruction_context
|
instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 1)?
|
.try_borrow_instruction_account(transaction_context, 1)?
|
||||||
.set_data(vec![0; 40])?;
|
.set_data(vec![0; 40])?;
|
||||||
|
@ -10406,11 +10418,13 @@ fn test_compute_budget_program_noop() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
ComputeBudget {
|
ComputeBudget {
|
||||||
compute_unit_limit: 1,
|
compute_unit_limit: compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
|
||||||
heap_size: Some(48 * 1024),
|
heap_size: Some(48 * 1024),
|
||||||
..ComputeBudget::default()
|
..ComputeBudget::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -10418,7 +10432,9 @@ fn test_compute_budget_program_noop() {
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
ComputeBudgetInstruction::set_compute_unit_limit(1),
|
ComputeBudgetInstruction::set_compute_unit_limit(
|
||||||
|
compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT,
|
||||||
|
),
|
||||||
ComputeBudgetInstruction::request_heap_frame(48 * 1024),
|
ComputeBudgetInstruction::request_heap_frame(48 * 1024),
|
||||||
Instruction::new_with_bincode(program_id, &0, vec![]),
|
Instruction::new_with_bincode(program_id, &0, vec![]),
|
||||||
],
|
],
|
||||||
|
@ -10449,11 +10465,13 @@ fn test_compute_request_instruction() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
ComputeBudget {
|
ComputeBudget {
|
||||||
compute_unit_limit: 1,
|
compute_unit_limit: compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
|
||||||
heap_size: Some(48 * 1024),
|
heap_size: Some(48 * 1024),
|
||||||
..ComputeBudget::default()
|
..ComputeBudget::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -10461,7 +10479,9 @@ fn test_compute_request_instruction() {
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
ComputeBudgetInstruction::set_compute_unit_limit(1),
|
ComputeBudgetInstruction::set_compute_unit_limit(
|
||||||
|
compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT,
|
||||||
|
),
|
||||||
ComputeBudgetInstruction::request_heap_frame(48 * 1024),
|
ComputeBudgetInstruction::request_heap_frame(48 * 1024),
|
||||||
Instruction::new_with_bincode(program_id, &0, vec![]),
|
Instruction::new_with_bincode(program_id, &0, vec![]),
|
||||||
],
|
],
|
||||||
|
@ -10499,7 +10519,7 @@ fn test_failed_compute_request_instruction() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
ComputeBudget {
|
ComputeBudget {
|
||||||
compute_unit_limit: 1,
|
compute_unit_limit: compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
|
||||||
heap_size: Some(48 * 1024),
|
heap_size: Some(48 * 1024),
|
||||||
..ComputeBudget::default()
|
..ComputeBudget::default()
|
||||||
}
|
}
|
||||||
|
@ -11063,6 +11083,8 @@ fn mock_transfer_process_instruction(
|
||||||
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();
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockTransferInstruction::Transfer(amount) => {
|
MockTransferInstruction::Transfer(amount) => {
|
||||||
|
@ -11871,6 +11893,8 @@ fn mock_realloc_process_instruction(
|
||||||
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();
|
||||||
|
// mock builtin must consume units
|
||||||
|
invoke_context.consume_checked(1)?;
|
||||||
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockReallocInstruction::Realloc(new_size, new_balance, _) => {
|
MockReallocInstruction::Realloc(new_size, new_balance, _) => {
|
||||||
|
|
|
@ -223,6 +223,8 @@ mod tests {
|
||||||
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();
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockSystemInstruction::Correct => Ok(()),
|
MockSystemInstruction::Correct => Ok(()),
|
||||||
|
@ -436,6 +438,8 @@ mod tests {
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
let mut to_account =
|
let mut to_account =
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockSystemInstruction::BorrowFail => {
|
MockSystemInstruction::BorrowFail => {
|
||||||
|
@ -642,8 +646,10 @@ mod tests {
|
||||||
fn test_precompile() {
|
fn test_precompile() {
|
||||||
let mock_program_id = Pubkey::new_unique();
|
let mock_program_id = Pubkey::new_unique();
|
||||||
fn mock_process_instruction(
|
fn mock_process_instruction(
|
||||||
_invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
|
// mock builtin should consume units
|
||||||
|
let _ = invoke_context.consume_checked(1);
|
||||||
Err(InstructionError::Custom(0xbabb1e))
|
Err(InstructionError::Custom(0xbabb1e))
|
||||||
}
|
}
|
||||||
let builtin_programs = &[BuiltinProgram {
|
let builtin_programs = &[BuiltinProgram {
|
||||||
|
|
|
@ -323,6 +323,14 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", instruction);
|
trace!("process_instruction: {:?}", instruction);
|
||||||
|
|
||||||
|
// Consume compute units if feature `native_programs_consume_cu` is activated,
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked(150)?;
|
||||||
|
}
|
||||||
|
|
||||||
let signers = instruction_context.get_signers(transaction_context)?;
|
let signers = instruction_context.get_signers(transaction_context)?;
|
||||||
match instruction {
|
match instruction {
|
||||||
SystemInstruction::CreateAccount {
|
SystemInstruction::CreateAccount {
|
||||||
|
|
|
@ -260,6 +260,10 @@ pub enum InstructionError {
|
||||||
/// Max instruction trace length exceeded
|
/// Max instruction trace length exceeded
|
||||||
#[error("Max instruction trace length exceeded")]
|
#[error("Max instruction trace length exceeded")]
|
||||||
MaxInstructionTraceLengthExceeded,
|
MaxInstructionTraceLengthExceeded,
|
||||||
|
|
||||||
|
/// Builtin programs must consume compute units
|
||||||
|
#[error("Builtin programs must consume compute units")]
|
||||||
|
BuiltinProgramsMustConsumeComputeUnits,
|
||||||
// Note: For any new error added here an equivalent ProgramError and its
|
// Note: For any new error added here an equivalent ProgramError and its
|
||||||
// conversions must also be added
|
// conversions must also be added
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ pub enum ProgramError {
|
||||||
InvalidRealloc,
|
InvalidRealloc,
|
||||||
#[error("Instruction trace length exceeded the maximum allowed per transaction")]
|
#[error("Instruction trace length exceeded the maximum allowed per transaction")]
|
||||||
MaxInstructionTraceLengthExceeded,
|
MaxInstructionTraceLengthExceeded,
|
||||||
|
#[error("Builtin programs must consume compute units")]
|
||||||
|
BuiltinProgramsMustConsumeComputeUnits,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PrintProgramError {
|
pub trait PrintProgramError {
|
||||||
|
@ -102,6 +104,9 @@ impl PrintProgramError for ProgramError {
|
||||||
Self::MaxInstructionTraceLengthExceeded => {
|
Self::MaxInstructionTraceLengthExceeded => {
|
||||||
msg!("Error: MaxInstructionTraceLengthExceeded")
|
msg!("Error: MaxInstructionTraceLengthExceeded")
|
||||||
}
|
}
|
||||||
|
Self::BuiltinProgramsMustConsumeComputeUnits => {
|
||||||
|
msg!("Error: BuiltinProgramsMustConsumeComputeUnits")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,6 +140,7 @@ pub const ILLEGAL_OWNER: u64 = to_builtin!(18);
|
||||||
pub const MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED: u64 = to_builtin!(19);
|
pub const MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED: u64 = to_builtin!(19);
|
||||||
pub const INVALID_ACCOUNT_DATA_REALLOC: u64 = to_builtin!(20);
|
pub const INVALID_ACCOUNT_DATA_REALLOC: u64 = to_builtin!(20);
|
||||||
pub const MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED: u64 = to_builtin!(21);
|
pub const MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED: u64 = to_builtin!(21);
|
||||||
|
pub const BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS: u64 = to_builtin!(22);
|
||||||
// Warning: Any new program errors added here must also be:
|
// Warning: Any new program errors added here must also be:
|
||||||
// - Added to the below conversions
|
// - Added to the below conversions
|
||||||
// - Added as an equivalent to InstructionError
|
// - Added as an equivalent to InstructionError
|
||||||
|
@ -168,6 +174,9 @@ impl From<ProgramError> for u64 {
|
||||||
ProgramError::MaxInstructionTraceLengthExceeded => {
|
ProgramError::MaxInstructionTraceLengthExceeded => {
|
||||||
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED
|
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED
|
||||||
}
|
}
|
||||||
|
ProgramError::BuiltinProgramsMustConsumeComputeUnits => {
|
||||||
|
BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS
|
||||||
|
}
|
||||||
ProgramError::Custom(error) => {
|
ProgramError::Custom(error) => {
|
||||||
if error == 0 {
|
if error == 0 {
|
||||||
CUSTOM_ZERO
|
CUSTOM_ZERO
|
||||||
|
@ -203,6 +212,9 @@ impl From<u64> for ProgramError {
|
||||||
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
|
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
|
||||||
INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
|
INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
|
||||||
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
|
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
|
||||||
|
BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS => {
|
||||||
|
Self::BuiltinProgramsMustConsumeComputeUnits
|
||||||
|
}
|
||||||
_ => Self::Custom(error as u32),
|
_ => Self::Custom(error as u32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,6 +250,9 @@ impl TryFrom<InstructionError> for ProgramError {
|
||||||
Self::Error::MaxInstructionTraceLengthExceeded => {
|
Self::Error::MaxInstructionTraceLengthExceeded => {
|
||||||
Ok(Self::MaxInstructionTraceLengthExceeded)
|
Ok(Self::MaxInstructionTraceLengthExceeded)
|
||||||
}
|
}
|
||||||
|
Self::Error::BuiltinProgramsMustConsumeComputeUnits => {
|
||||||
|
Ok(Self::BuiltinProgramsMustConsumeComputeUnits)
|
||||||
|
}
|
||||||
_ => Err(error),
|
_ => Err(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,6 +286,9 @@ where
|
||||||
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
|
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED => Self::MaxAccountsDataAllocationsExceeded,
|
||||||
INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
|
INVALID_ACCOUNT_DATA_REALLOC => Self::InvalidRealloc,
|
||||||
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
|
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED => Self::MaxInstructionTraceLengthExceeded,
|
||||||
|
BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS => {
|
||||||
|
Self::BuiltinProgramsMustConsumeComputeUnits
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// A valid custom error has no bits set in the upper 32
|
// A valid custom error has no bits set in the upper 32
|
||||||
if error >> BUILTIN_BIT_SHIFT == 0 {
|
if error >> BUILTIN_BIT_SHIFT == 0 {
|
||||||
|
|
|
@ -638,6 +638,10 @@ pub mod include_loaded_accounts_data_size_in_fee_calculation {
|
||||||
solana_sdk::declare_id!("EaQpmC6GtRssaZ3PCUM5YksGqUdMLeZ46BQXYtHYakDS");
|
solana_sdk::declare_id!("EaQpmC6GtRssaZ3PCUM5YksGqUdMLeZ46BQXYtHYakDS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod native_programs_consume_cu {
|
||||||
|
solana_sdk::declare_id!("8pgXCMNXC8qyEFypuwpXyRxLXZdpM4Qo72gJ6k87A6wL");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
|
@ -792,6 +796,7 @@ lazy_static! {
|
||||||
(round_up_heap_size::id(), "round up heap size when calculating heap cost #30679"),
|
(round_up_heap_size::id(), "round up heap size when calculating heap cost #30679"),
|
||||||
(remove_bpf_loader_incorrect_program_id::id(), "stop incorrectly throwing IncorrectProgramId in bpf_loader #30747"),
|
(remove_bpf_loader_incorrect_program_id::id(), "stop incorrectly throwing IncorrectProgramId in bpf_loader #30747"),
|
||||||
(include_loaded_accounts_data_size_in_fee_calculation::id(), "include transaction loaded accounts data size in base fee calculation #30657"),
|
(include_loaded_accounts_data_size_in_fee_calculation::id(), "include transaction loaded accounts data size in base fee calculation #30657"),
|
||||||
|
(native_programs_consume_cu::id(), "Native program should consume compute units #30620"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -125,6 +125,7 @@ enum InstructionErrorType {
|
||||||
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED = 50;
|
MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED = 50;
|
||||||
MAX_ACCOUNTS_EXCEEDED = 51;
|
MAX_ACCOUNTS_EXCEEDED = 51;
|
||||||
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED = 52;
|
MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED = 52;
|
||||||
|
BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS = 53;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UnixTimestamp {
|
message UnixTimestamp {
|
||||||
|
|
|
@ -745,6 +745,7 @@ impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
|
||||||
50 => InstructionError::MaxAccountsDataAllocationsExceeded,
|
50 => InstructionError::MaxAccountsDataAllocationsExceeded,
|
||||||
51 => InstructionError::MaxAccountsExceeded,
|
51 => InstructionError::MaxAccountsExceeded,
|
||||||
52 => InstructionError::MaxInstructionTraceLengthExceeded,
|
52 => InstructionError::MaxInstructionTraceLengthExceeded,
|
||||||
|
53 => InstructionError::BuiltinProgramsMustConsumeComputeUnits,
|
||||||
_ => return Err("Invalid InstructionError"),
|
_ => return Err("Invalid InstructionError"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1075,6 +1076,9 @@ impl From<TransactionError> for tx_by_addr::TransactionError {
|
||||||
InstructionError::MaxInstructionTraceLengthExceeded => {
|
InstructionError::MaxInstructionTraceLengthExceeded => {
|
||||||
tx_by_addr::InstructionErrorType::MaxInstructionTraceLengthExceeded
|
tx_by_addr::InstructionErrorType::MaxInstructionTraceLengthExceeded
|
||||||
}
|
}
|
||||||
|
InstructionError::BuiltinProgramsMustConsumeComputeUnits => {
|
||||||
|
tx_by_addr::InstructionErrorType::BuiltinProgramsMustConsumeComputeUnits
|
||||||
|
}
|
||||||
} as i32,
|
} as i32,
|
||||||
custom: match instruction_error {
|
custom: match instruction_error {
|
||||||
InstructionError::Custom(custom) => {
|
InstructionError::Custom(custom) => {
|
||||||
|
|
Loading…
Reference in New Issue