* Add program heap bump instruction (#20607)
(cherry picked from commit 58164517e4
)
* nudge
Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
@ -193,6 +193,54 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_create_vm(bencher: &mut Bencher) {
|
||||||
|
const BUDGET: u64 = 200_000;
|
||||||
|
let loader_id = bpf_loader::id();
|
||||||
|
|
||||||
|
let accounts = [RefCell::new(AccountSharedData::new(
|
||||||
|
1,
|
||||||
|
10000001,
|
||||||
|
&solana_sdk::pubkey::new_rand(),
|
||||||
|
))];
|
||||||
|
let keys = [solana_sdk::pubkey::new_rand()];
|
||||||
|
let keyed_accounts: Vec<_> = keys
|
||||||
|
.iter()
|
||||||
|
.zip(&accounts)
|
||||||
|
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
|
||||||
|
.collect();
|
||||||
|
let instruction_data = vec![0u8];
|
||||||
|
|
||||||
|
let mut invoke_context = MockInvokeContext::new(keyed_accounts);
|
||||||
|
invoke_context.compute_meter.remaining = BUDGET;
|
||||||
|
|
||||||
|
// Serialize account data
|
||||||
|
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
|
||||||
|
let mut serialized = serialize_parameters(
|
||||||
|
&bpf_loader::id(),
|
||||||
|
&solana_sdk::pubkey::new_rand(),
|
||||||
|
keyed_accounts,
|
||||||
|
&instruction_data,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let elf = load_elf("noop").unwrap();
|
||||||
|
let mut executable =
|
||||||
|
<dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
|
||||||
|
.unwrap();
|
||||||
|
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
|
||||||
|
|
||||||
|
bencher.iter(|| {
|
||||||
|
let _ = create_vm(
|
||||||
|
&loader_id,
|
||||||
|
executable.as_ref(),
|
||||||
|
serialized.as_slice_mut(),
|
||||||
|
&mut invoke_context,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
||||||
const BUDGET: u64 = 200_000;
|
const BUDGET: u64 = 200_000;
|
||||||
|
@ -34,7 +34,7 @@ use solana_sdk::{
|
|||||||
entrypoint::{HEAP_LENGTH, SUCCESS},
|
entrypoint::{HEAP_LENGTH, SUCCESS},
|
||||||
feature_set::{
|
feature_set::{
|
||||||
add_missing_program_error_mappings, close_upgradeable_program_accounts, fix_write_privs,
|
add_missing_program_error_mappings, close_upgradeable_program_accounts, fix_write_privs,
|
||||||
reduce_required_deploy_balance, upgradeable_close_instruction,
|
reduce_required_deploy_balance, requestable_heap_size, upgradeable_close_instruction,
|
||||||
},
|
},
|
||||||
ic_logger_msg, ic_msg,
|
ic_logger_msg, ic_msg,
|
||||||
instruction::{AccountMeta, InstructionError},
|
instruction::{AccountMeta, InstructionError},
|
||||||
@ -150,6 +150,12 @@ pub fn create_vm<'a>(
|
|||||||
invoke_context: &'a mut dyn InvokeContext,
|
invoke_context: &'a mut dyn InvokeContext,
|
||||||
) -> Result<EbpfVm<'a, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> {
|
) -> Result<EbpfVm<'a, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> {
|
||||||
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
|
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
|
||||||
|
let heap_size = bpf_compute_budget.heap_size.unwrap_or(HEAP_LENGTH);
|
||||||
|
if invoke_context.is_feature_active(&requestable_heap_size::id()) {
|
||||||
|
let _ = invoke_context.get_compute_meter().borrow_mut().consume(
|
||||||
|
(heap_size as u64 / (32 * 1024)).saturating_sub(1) * bpf_compute_budget.heap_cost,
|
||||||
|
);
|
||||||
|
}
|
||||||
let heap = AlignedMemory::new_with_size(
|
let heap = AlignedMemory::new_with_size(
|
||||||
bpf_compute_budget.heap_size.unwrap_or(HEAP_LENGTH),
|
bpf_compute_budget.heap_size.unwrap_or(HEAP_LENGTH),
|
||||||
HOST_ALIGN,
|
HOST_ALIGN,
|
||||||
|
@ -3677,7 +3677,11 @@ impl Bank {
|
|||||||
.unwrap_or_else(BpfComputeBudget::new);
|
.unwrap_or_else(BpfComputeBudget::new);
|
||||||
|
|
||||||
let mut process_result = if feature_set.is_active(&tx_wide_compute_cap::id()) {
|
let mut process_result = if feature_set.is_active(&tx_wide_compute_cap::id()) {
|
||||||
compute_budget::process_request(&mut bpf_compute_budget, tx)
|
compute_budget::process_request(
|
||||||
|
&mut bpf_compute_budget,
|
||||||
|
tx,
|
||||||
|
feature_set.clone(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
@ -14253,6 +14257,7 @@ pub(crate) mod tests {
|
|||||||
*compute_budget,
|
*compute_budget,
|
||||||
BpfComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 1,
|
max_units: 1,
|
||||||
|
heap_size: Some(48 * 1024),
|
||||||
..BpfComputeBudget::default()
|
..BpfComputeBudget::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -14264,6 +14269,7 @@ pub(crate) mod tests {
|
|||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
compute_budget::request_units(1),
|
compute_budget::request_units(1),
|
||||||
|
compute_budget::request_heap_frame(48 * 1024),
|
||||||
Instruction::new_with_bincode(program_id, &0, vec![]),
|
Instruction::new_with_bincode(program_id, &0, vec![]),
|
||||||
],
|
],
|
||||||
Some(&mint_keypair.pubkey()),
|
Some(&mint_keypair.pubkey()),
|
||||||
|
@ -11,8 +11,8 @@ use solana_sdk::{
|
|||||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||||
feature_set::{
|
feature_set::{
|
||||||
demote_program_write_locks, fix_write_privs, instructions_sysvar_enabled,
|
demote_program_write_locks, fix_write_privs, instructions_sysvar_enabled,
|
||||||
neon_evm_compute_budget, remove_native_loader, tx_wide_compute_cap, updated_verify_policy,
|
neon_evm_compute_budget, remove_native_loader, requestable_heap_size, tx_wide_compute_cap,
|
||||||
FeatureSet,
|
updated_verify_policy, FeatureSet,
|
||||||
},
|
},
|
||||||
ic_logger_msg, ic_msg,
|
ic_logger_msg, ic_msg,
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
@ -1227,11 +1227,17 @@ impl MessageProcessor {
|
|||||||
let program_id = instruction.program_id(&message.account_keys);
|
let program_id = instruction.program_id(&message.account_keys);
|
||||||
|
|
||||||
let mut bpf_compute_budget = bpf_compute_budget;
|
let mut bpf_compute_budget = bpf_compute_budget;
|
||||||
if feature_set.is_active(&neon_evm_compute_budget::id())
|
if !feature_set.is_active(&tx_wide_compute_cap::id())
|
||||||
|
&& feature_set.is_active(&neon_evm_compute_budget::id())
|
||||||
&& *program_id == crate::neon_evm_program::id()
|
&& *program_id == crate::neon_evm_program::id()
|
||||||
{
|
{
|
||||||
// Bump the compute budget for neon_evm
|
// Bump the compute budget for neon_evm
|
||||||
bpf_compute_budget.max_units = bpf_compute_budget.max_units.max(500_000);
|
bpf_compute_budget.max_units = bpf_compute_budget.max_units.max(500_000);
|
||||||
|
}
|
||||||
|
if !feature_set.is_active(&requestable_heap_size::id())
|
||||||
|
&& feature_set.is_active(&neon_evm_compute_budget::id())
|
||||||
|
&& *program_id == crate::neon_evm_program::id()
|
||||||
|
{
|
||||||
bpf_compute_budget.heap_size = Some(256 * 1024);
|
bpf_compute_budget.heap_size = Some(256 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![cfg(feature = "full")]
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
entrypoint::HEAP_LENGTH as MIN_HEAP_FRAME_BYTES,
|
||||||
|
feature_set::{requestable_heap_size, FeatureSet},
|
||||||
process_instruction::BpfComputeBudget,
|
process_instruction::BpfComputeBudget,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
@ -9,10 +11,12 @@ use solana_sdk::{
|
|||||||
borsh::try_from_slice_unchecked,
|
borsh::try_from_slice_unchecked,
|
||||||
instruction::{Instruction, InstructionError},
|
instruction::{Instruction, InstructionError},
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
crate::declare_id!("ComputeBudget111111111111111111111111111111");
|
crate::declare_id!("ComputeBudget111111111111111111111111111111");
|
||||||
|
|
||||||
const MAX_UNITS: u32 = 1_000_000;
|
const MAX_UNITS: u32 = 1_000_000;
|
||||||
|
const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
|
||||||
|
|
||||||
/// Compute Budget Instructions
|
/// Compute Budget Instructions
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -31,6 +35,10 @@ pub enum ComputeBudgetInstruction {
|
|||||||
/// Request a specific maximum number of compute units the transaction is
|
/// Request a specific maximum number of compute units the transaction is
|
||||||
/// allowed to consume.
|
/// allowed to consume.
|
||||||
RequestUnits(u32),
|
RequestUnits(u32),
|
||||||
|
/// Request a specific transaction-wide program heap frame size in bytes.
|
||||||
|
/// The value requested must be a multiple of 1024. This new heap frame size
|
||||||
|
/// applies to each program executed, including all calls to CPIs.
|
||||||
|
RequestHeapFrame(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `ComputeBudgetInstruction::RequestUnits` `Instruction`
|
/// Create a `ComputeBudgetInstruction::RequestUnits` `Instruction`
|
||||||
@ -38,22 +46,45 @@ pub fn request_units(units: u32) -> Instruction {
|
|||||||
Instruction::new_with_borsh(id(), &ComputeBudgetInstruction::RequestUnits(units), vec![])
|
Instruction::new_with_borsh(id(), &ComputeBudgetInstruction::RequestUnits(units), vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a `ComputeBudgetInstruction::RequestHeapFrame` `Instruction`
|
||||||
|
pub fn request_heap_frame(bytes: u32) -> Instruction {
|
||||||
|
Instruction::new_with_borsh(
|
||||||
|
id(),
|
||||||
|
&ComputeBudgetInstruction::RequestHeapFrame(bytes),
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_request(
|
pub fn process_request(
|
||||||
compute_budget: &mut BpfComputeBudget,
|
compute_budget: &mut BpfComputeBudget,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
|
feature_set: Arc<FeatureSet>,
|
||||||
) -> Result<(), TransactionError> {
|
) -> Result<(), TransactionError> {
|
||||||
let error = TransactionError::InstructionError(0, InstructionError::InvalidInstructionData);
|
let error = TransactionError::InstructionError(0, InstructionError::InvalidInstructionData);
|
||||||
// Compute budget instruction must be in 1st or 2nd instruction (avoid nonce marker)
|
// Compute budget instruction must be in the 1st 3 instructions (avoid
|
||||||
for instruction in tx.message().instructions.iter().take(2) {
|
// nonce marker), otherwise ignored
|
||||||
|
for instruction in tx.message().instructions.iter().take(3) {
|
||||||
if check_id(instruction.program_id(&tx.message().account_keys)) {
|
if check_id(instruction.program_id(&tx.message().account_keys)) {
|
||||||
let ComputeBudgetInstruction::RequestUnits(units) =
|
match try_from_slice_unchecked(&instruction.data) {
|
||||||
try_from_slice_unchecked::<ComputeBudgetInstruction>(&instruction.data)
|
Ok(ComputeBudgetInstruction::RequestUnits(units)) => {
|
||||||
.map_err(|_| error.clone())?;
|
|
||||||
if units > MAX_UNITS {
|
if units > MAX_UNITS {
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
compute_budget.max_units = units as u64;
|
compute_budget.max_units = units as u64;
|
||||||
}
|
}
|
||||||
|
Ok(ComputeBudgetInstruction::RequestHeapFrame(bytes)) => {
|
||||||
|
if !feature_set.is_active(&requestable_heap_size::id())
|
||||||
|
|| bytes > MAX_HEAP_FRAME_BYTES
|
||||||
|
|| bytes < MIN_HEAP_FRAME_BYTES as u32
|
||||||
|
|| bytes % 1024 != 0
|
||||||
|
{
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
compute_budget.heap_size = Some(bytes as usize);
|
||||||
|
}
|
||||||
|
_ => return Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -61,82 +92,153 @@ pub fn process_request(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{hash::Hash, message::Message, pubkey::Pubkey, signature::Keypair, signer::Signer};
|
||||||
compute_budget, hash::Hash, message::Message, pubkey::Pubkey, signature::Keypair,
|
|
||||||
signer::Signer,
|
macro_rules! test {
|
||||||
|
( $instructions: expr, $expected_error: expr, $expected_budget: expr ) => {
|
||||||
|
let payer_keypair = Keypair::new();
|
||||||
|
let tx = Transaction::new(
|
||||||
|
&[&payer_keypair],
|
||||||
|
Message::new($instructions, Some(&payer_keypair.pubkey())),
|
||||||
|
Hash::default(),
|
||||||
|
);
|
||||||
|
let feature_set = Arc::new(FeatureSet::all_enabled());
|
||||||
|
let mut compute_budget = BpfComputeBudget::default();
|
||||||
|
let result = process_request(&mut compute_budget, &tx, feature_set);
|
||||||
|
assert_eq!($expected_error as Result<(), TransactionError>, result);
|
||||||
|
assert_eq!(compute_budget, $expected_budget);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_process_request() {
|
fn test_process_request() {
|
||||||
let payer_keypair = Keypair::new();
|
// Units
|
||||||
let mut compute_budget = BpfComputeBudget::default();
|
test!(&[], Ok(()), BpfComputeBudget::default());
|
||||||
|
test!(
|
||||||
let tx = Transaction::new(
|
|
||||||
&[&payer_keypair],
|
|
||||||
Message::new(&[], Some(&payer_keypair.pubkey())),
|
|
||||||
Hash::default(),
|
|
||||||
);
|
|
||||||
process_request(&mut compute_budget, &tx).unwrap();
|
|
||||||
assert_eq!(compute_budget, BpfComputeBudget::default());
|
|
||||||
|
|
||||||
let tx = Transaction::new(
|
|
||||||
&[&payer_keypair],
|
|
||||||
Message::new(
|
|
||||||
&[
|
&[
|
||||||
compute_budget::request_units(1),
|
request_units(1),
|
||||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
],
|
],
|
||||||
Some(&payer_keypair.pubkey()),
|
Ok(()),
|
||||||
),
|
|
||||||
Hash::default(),
|
|
||||||
);
|
|
||||||
process_request(&mut compute_budget, &tx).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
compute_budget,
|
|
||||||
BpfComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 1,
|
max_units: 1,
|
||||||
..BpfComputeBudget::default()
|
..BpfComputeBudget::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
let tx = Transaction::new(
|
|
||||||
&[&payer_keypair],
|
|
||||||
Message::new(
|
|
||||||
&[
|
&[
|
||||||
compute_budget::request_units(MAX_UNITS + 1),
|
request_units(MAX_UNITS + 1),
|
||||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
],
|
],
|
||||||
Some(&payer_keypair.pubkey()),
|
|
||||||
),
|
|
||||||
Hash::default(),
|
|
||||||
);
|
|
||||||
let result = process_request(&mut compute_budget, &tx);
|
|
||||||
assert_eq!(
|
|
||||||
result,
|
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::InvalidInstructionData
|
InstructionError::InvalidInstructionData,
|
||||||
))
|
)),
|
||||||
|
BpfComputeBudget::default()
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
let tx = Transaction::new(
|
|
||||||
&[&payer_keypair],
|
|
||||||
Message::new(
|
|
||||||
&[
|
&[
|
||||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
compute_budget::request_units(MAX_UNITS),
|
request_units(MAX_UNITS),
|
||||||
],
|
],
|
||||||
Some(&payer_keypair.pubkey()),
|
Ok(()),
|
||||||
),
|
|
||||||
Hash::default(),
|
|
||||||
);
|
|
||||||
process_request(&mut compute_budget, &tx).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
compute_budget,
|
|
||||||
BpfComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: MAX_UNITS as u64,
|
max_units: MAX_UNITS as u64,
|
||||||
..BpfComputeBudget::default()
|
..BpfComputeBudget::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
request_units(1),
|
||||||
|
],
|
||||||
|
Ok(()),
|
||||||
|
BpfComputeBudget::default()
|
||||||
|
);
|
||||||
|
|
||||||
|
// HeapFrame
|
||||||
|
test!(&[], Ok(()), BpfComputeBudget::default());
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
request_heap_frame(40 * 1024),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
],
|
||||||
|
Ok(()),
|
||||||
|
BpfComputeBudget {
|
||||||
|
heap_size: Some(40 * 1024),
|
||||||
|
..BpfComputeBudget::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
request_heap_frame(40 * 1024 + 1),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
],
|
||||||
|
Err(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::InvalidInstructionData,
|
||||||
|
)),
|
||||||
|
BpfComputeBudget::default()
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
request_heap_frame(31 * 1024),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
],
|
||||||
|
Err(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::InvalidInstructionData,
|
||||||
|
)),
|
||||||
|
BpfComputeBudget::default()
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
request_heap_frame(MAX_HEAP_FRAME_BYTES + 1),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
],
|
||||||
|
Err(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::InvalidInstructionData,
|
||||||
|
)),
|
||||||
|
BpfComputeBudget::default()
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
request_heap_frame(MAX_HEAP_FRAME_BYTES),
|
||||||
|
],
|
||||||
|
Ok(()),
|
||||||
|
BpfComputeBudget {
|
||||||
|
heap_size: Some(MAX_HEAP_FRAME_BYTES as usize),
|
||||||
|
..BpfComputeBudget::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
request_heap_frame(1), // ignored
|
||||||
|
],
|
||||||
|
Ok(()),
|
||||||
|
BpfComputeBudget::default()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Combined
|
||||||
|
test!(
|
||||||
|
&[
|
||||||
|
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||||
|
request_heap_frame(MAX_HEAP_FRAME_BYTES),
|
||||||
|
request_units(MAX_UNITS),
|
||||||
|
],
|
||||||
|
Ok(()),
|
||||||
|
BpfComputeBudget {
|
||||||
|
max_units: MAX_UNITS as u64,
|
||||||
|
heap_size: Some(MAX_HEAP_FRAME_BYTES as usize),
|
||||||
|
..BpfComputeBudget::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +243,10 @@ pub mod ed25519_program_enabled {
|
|||||||
solana_sdk::declare_id!("E1TvTNipX8TKNHrhRC8SMuAwQmGY58TZ4drdztP3Gxwc");
|
solana_sdk::declare_id!("E1TvTNipX8TKNHrhRC8SMuAwQmGY58TZ4drdztP3Gxwc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod requestable_heap_size {
|
||||||
|
solana_sdk::declare_id!("CCu4boMmfLuqcmfTLPHQiUo22ZdUsXjgzPAURYaWt1Bw");
|
||||||
|
}
|
||||||
|
|
||||||
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> = [
|
||||||
@ -304,6 +308,7 @@ lazy_static! {
|
|||||||
(return_data_syscall_enabled::id(), "enable sol_{set,get}_return_data syscall"),
|
(return_data_syscall_enabled::id(), "enable sol_{set,get}_return_data syscall"),
|
||||||
(sol_log_data_syscall_enabled::id(), "enable sol_log_data syscall"),
|
(sol_log_data_syscall_enabled::id(), "enable sol_log_data syscall"),
|
||||||
(ed25519_program_enabled::id(), "enable builtin ed25519 signature verify program"),
|
(ed25519_program_enabled::id(), "enable builtin ed25519 signature verify program"),
|
||||||
|
(requestable_heap_size::id(), "Requestable heap frame size"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -190,6 +190,9 @@ pub struct BpfComputeBudget {
|
|||||||
pub syscall_base_cost: u64,
|
pub syscall_base_cost: u64,
|
||||||
/// Optional program heap region size, if `None` then loader default
|
/// Optional program heap region size, if `None` then loader default
|
||||||
pub heap_size: Option<usize>,
|
pub heap_size: Option<usize>,
|
||||||
|
/// Number of compute units per additional 32k heap above the default (~.5
|
||||||
|
/// us per 32k at 15 units/us rounded up)
|
||||||
|
pub heap_cost: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BpfComputeBudget {
|
impl Default for BpfComputeBudget {
|
||||||
@ -217,6 +220,7 @@ impl BpfComputeBudget {
|
|||||||
syscall_base_cost: 100,
|
syscall_base_cost: 100,
|
||||||
secp256k1_recover_cost: 25_000,
|
secp256k1_recover_cost: 25_000,
|
||||||
heap_size: None,
|
heap_size: None,
|
||||||
|
heap_cost: 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user