Rename BpfComputeBudget (#18768)
This commit is contained in:
@ -1,9 +1,6 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use crate::{
|
||||
process_instruction::BpfComputeBudget,
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use crate::transaction::{Transaction, TransactionError};
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
use solana_sdk::{
|
||||
borsh::try_from_slice_unchecked,
|
||||
@ -32,70 +29,126 @@ pub enum ComputeBudgetInstruction {
|
||||
/// allowed to consume.
|
||||
RequestUnits(u64),
|
||||
}
|
||||
|
||||
/// Create a `ComputeBudgetInstruction::RequestUnits` `Instruction`
|
||||
pub fn request_units(units: u64) -> Instruction {
|
||||
Instruction::new_with_borsh(id(), &ComputeBudgetInstruction::RequestUnits(units), vec![])
|
||||
impl ComputeBudgetInstruction {
|
||||
/// Create a `ComputeBudgetInstruction::RequestUnits` `Instruction`
|
||||
pub fn request_units(units: u64) -> Instruction {
|
||||
Instruction::new_with_borsh(id(), &ComputeBudgetInstruction::RequestUnits(units), vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_request(
|
||||
compute_budget: &mut BpfComputeBudget,
|
||||
tx: &Transaction,
|
||||
) -> Result<(), TransactionError> {
|
||||
let error = TransactionError::InstructionError(0, InstructionError::InvalidInstructionData);
|
||||
// Compute budget instruction must be in 1st or 2nd instruction (avoid nonce marker)
|
||||
for instruction in tx.message().instructions.iter().take(2) {
|
||||
if check_id(instruction.program_id(&tx.message().account_keys)) {
|
||||
let ComputeBudgetInstruction::RequestUnits(units) =
|
||||
try_from_slice_unchecked::<ComputeBudgetInstruction>(&instruction.data)
|
||||
.map_err(|_| error.clone())?;
|
||||
if units > MAX_UNITS {
|
||||
return Err(error);
|
||||
}
|
||||
compute_budget.max_units = units;
|
||||
#[derive(Clone, Copy, Debug, AbiExample, PartialEq)]
|
||||
pub struct ComputeBudget {
|
||||
/// Number of compute units that an instruction is allowed. Compute units
|
||||
/// are consumed by program execution, resources they use, etc...
|
||||
pub max_units: u64,
|
||||
/// Number of compute units consumed by a log_u64 call
|
||||
pub log_64_units: u64,
|
||||
/// Number of compute units consumed by a create_program_address call
|
||||
pub create_program_address_units: u64,
|
||||
/// Number of compute units consumed by an invoke call (not including the cost incurred by
|
||||
/// the called program)
|
||||
pub invoke_units: u64,
|
||||
/// Maximum cross-program invocation depth allowed
|
||||
pub max_invoke_depth: usize,
|
||||
/// Base number of compute units consumed to call SHA256
|
||||
pub sha256_base_cost: u64,
|
||||
/// Incremental number of units consumed by SHA256 (based on bytes)
|
||||
pub sha256_byte_cost: u64,
|
||||
/// Maximum BPF to BPF call depth
|
||||
pub max_call_depth: usize,
|
||||
/// Size of a stack frame in bytes, must match the size specified in the LLVM BPF backend
|
||||
pub stack_frame_size: usize,
|
||||
/// Number of compute units consumed by logging a `Pubkey`
|
||||
pub log_pubkey_units: u64,
|
||||
/// Maximum cross-program invocation instruction size
|
||||
pub max_cpi_instruction_size: usize,
|
||||
/// Number of account data bytes per conpute unit charged during a cross-program invocation
|
||||
pub cpi_bytes_per_unit: u64,
|
||||
/// Base number of compute units consumed to get a sysvar
|
||||
pub sysvar_base_cost: u64,
|
||||
/// Number of compute units consumed to call secp256k1_recover
|
||||
pub secp256k1_recover_cost: u64,
|
||||
/// Optional program heap region size, if `None` then loader default
|
||||
pub heap_size: Option<usize>,
|
||||
}
|
||||
impl Default for ComputeBudget {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl ComputeBudget {
|
||||
pub fn new() -> Self {
|
||||
ComputeBudget {
|
||||
max_units: 200_000,
|
||||
log_64_units: 100,
|
||||
create_program_address_units: 1500,
|
||||
invoke_units: 1000,
|
||||
max_invoke_depth: 4,
|
||||
sha256_base_cost: 85,
|
||||
sha256_byte_cost: 1,
|
||||
max_call_depth: 64,
|
||||
stack_frame_size: 4_096,
|
||||
log_pubkey_units: 100,
|
||||
max_cpi_instruction_size: 1280, // IPv6 Min MTU size
|
||||
cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
|
||||
sysvar_base_cost: 100,
|
||||
secp256k1_recover_cost: 25_000,
|
||||
heap_size: None,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
pub fn process_transaction(&mut self, tx: &Transaction) -> Result<(), TransactionError> {
|
||||
let error = TransactionError::InstructionError(0, InstructionError::InvalidInstructionData);
|
||||
// Compute budget instruction must be in 1st or 2nd instruction (avoid nonce marker)
|
||||
for instruction in tx.message().instructions.iter().take(2) {
|
||||
if check_id(instruction.program_id(&tx.message().account_keys)) {
|
||||
let ComputeBudgetInstruction::RequestUnits(units) =
|
||||
try_from_slice_unchecked::<ComputeBudgetInstruction>(&instruction.data)
|
||||
.map_err(|_| error.clone())?;
|
||||
if units > MAX_UNITS {
|
||||
return Err(error);
|
||||
}
|
||||
self.max_units = units;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
compute_budget, hash::Hash, message::Message, pubkey::Pubkey, signature::Keypair,
|
||||
signer::Signer,
|
||||
};
|
||||
use crate::{hash::Hash, message::Message, pubkey::Pubkey, signature::Keypair, signer::Signer};
|
||||
|
||||
#[test]
|
||||
fn test_process_request() {
|
||||
fn test_process_transaction() {
|
||||
let payer_keypair = Keypair::new();
|
||||
let mut compute_budget = BpfComputeBudget::default();
|
||||
let mut compute_budget = ComputeBudget::default();
|
||||
|
||||
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());
|
||||
compute_budget.process_transaction(&tx).unwrap();
|
||||
assert_eq!(compute_budget, ComputeBudget::default());
|
||||
|
||||
let tx = Transaction::new(
|
||||
&[&payer_keypair],
|
||||
Message::new(
|
||||
&[
|
||||
compute_budget::request_units(1),
|
||||
ComputeBudgetInstruction::request_units(1),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||
],
|
||||
Some(&payer_keypair.pubkey()),
|
||||
),
|
||||
Hash::default(),
|
||||
);
|
||||
process_request(&mut compute_budget, &tx).unwrap();
|
||||
compute_budget.process_transaction(&tx).unwrap();
|
||||
assert_eq!(
|
||||
compute_budget,
|
||||
BpfComputeBudget {
|
||||
ComputeBudget {
|
||||
max_units: 1,
|
||||
..BpfComputeBudget::default()
|
||||
..ComputeBudget::default()
|
||||
}
|
||||
);
|
||||
|
||||
@ -103,14 +156,14 @@ mod tests {
|
||||
&[&payer_keypair],
|
||||
Message::new(
|
||||
&[
|
||||
compute_budget::request_units(MAX_UNITS + 1),
|
||||
ComputeBudgetInstruction::request_units(MAX_UNITS + 1),
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||
],
|
||||
Some(&payer_keypair.pubkey()),
|
||||
),
|
||||
Hash::default(),
|
||||
);
|
||||
let result = process_request(&mut compute_budget, &tx);
|
||||
let result = compute_budget.process_transaction(&tx);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(TransactionError::InstructionError(
|
||||
@ -124,18 +177,18 @@ mod tests {
|
||||
Message::new(
|
||||
&[
|
||||
Instruction::new_with_bincode(Pubkey::new_unique(), &0, vec![]),
|
||||
compute_budget::request_units(MAX_UNITS),
|
||||
ComputeBudgetInstruction::request_units(MAX_UNITS),
|
||||
],
|
||||
Some(&payer_keypair.pubkey()),
|
||||
),
|
||||
Hash::default(),
|
||||
);
|
||||
process_request(&mut compute_budget, &tx).unwrap();
|
||||
compute_budget.process_transaction(&tx).unwrap();
|
||||
assert_eq!(
|
||||
compute_budget,
|
||||
BpfComputeBudget {
|
||||
ComputeBudget {
|
||||
max_units: MAX_UNITS,
|
||||
..BpfComputeBudget::default()
|
||||
..ComputeBudget::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use crate::{
|
||||
account::{ReadableAccount, WritableAccount},
|
||||
account_utils::State as AccountUtilsState,
|
||||
|
@ -1,5 +1,8 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use solana_sdk::{
|
||||
account::AccountSharedData,
|
||||
compute_budget::ComputeBudget,
|
||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
||||
pubkey::Pubkey,
|
||||
@ -76,6 +79,8 @@ pub trait InvokeContext {
|
||||
/// Get this invocation's logger
|
||||
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
||||
/// Get this invocation's compute budget
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(since = "1.8.0", note = "please use `get_compute_budget` instead")]
|
||||
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget;
|
||||
/// Get this invocation's compute meter
|
||||
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
|
||||
@ -100,6 +105,8 @@ pub trait InvokeContext {
|
||||
);
|
||||
/// Get sysvar data
|
||||
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>>;
|
||||
/// Get this invocation's compute budget
|
||||
fn get_compute_budget(&self) -> &ComputeBudget;
|
||||
}
|
||||
|
||||
/// Convenience macro to log a message with an `Rc<RefCell<dyn Logger>>`
|
||||
@ -147,7 +154,8 @@ pub fn get_sysvar<T: Sysvar>(
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, AbiExample, PartialEq)]
|
||||
#[deprecated(since = "1.8.0", note = "please use `ComputeBudget` instead")]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct BpfComputeBudget {
|
||||
/// Number of compute units that an instruction is allowed. Compute units
|
||||
/// are consumed by program execution, resources they use, etc...
|
||||
@ -182,30 +190,60 @@ pub struct BpfComputeBudget {
|
||||
/// Optional program heap region size, if `None` then loader default
|
||||
pub heap_size: Option<usize>,
|
||||
}
|
||||
impl Default for BpfComputeBudget {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
#[allow(deprecated)]
|
||||
impl From<ComputeBudget> for BpfComputeBudget {
|
||||
fn from(item: ComputeBudget) -> Self {
|
||||
BpfComputeBudget {
|
||||
max_units: item.max_units,
|
||||
log_64_units: item.log_64_units,
|
||||
create_program_address_units: item.create_program_address_units,
|
||||
invoke_units: item.invoke_units,
|
||||
max_invoke_depth: item.max_invoke_depth,
|
||||
sha256_base_cost: item.sha256_base_cost,
|
||||
sha256_byte_cost: item.sha256_byte_cost,
|
||||
max_call_depth: item.max_call_depth,
|
||||
stack_frame_size: item.stack_frame_size,
|
||||
log_pubkey_units: item.log_pubkey_units,
|
||||
max_cpi_instruction_size: item.max_cpi_instruction_size,
|
||||
cpi_bytes_per_unit: item.cpi_bytes_per_unit,
|
||||
sysvar_base_cost: item.sysvar_base_cost,
|
||||
secp256k1_recover_cost: item.secp256k1_recover_cost,
|
||||
heap_size: item.heap_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
impl From<BpfComputeBudget> for ComputeBudget {
|
||||
fn from(item: BpfComputeBudget) -> Self {
|
||||
ComputeBudget {
|
||||
max_units: item.max_units,
|
||||
log_64_units: item.log_64_units,
|
||||
create_program_address_units: item.create_program_address_units,
|
||||
invoke_units: item.invoke_units,
|
||||
max_invoke_depth: item.max_invoke_depth,
|
||||
sha256_base_cost: item.sha256_base_cost,
|
||||
sha256_byte_cost: item.sha256_byte_cost,
|
||||
max_call_depth: item.max_call_depth,
|
||||
stack_frame_size: item.stack_frame_size,
|
||||
log_pubkey_units: item.log_pubkey_units,
|
||||
max_cpi_instruction_size: item.max_cpi_instruction_size,
|
||||
cpi_bytes_per_unit: item.cpi_bytes_per_unit,
|
||||
sysvar_base_cost: item.sysvar_base_cost,
|
||||
secp256k1_recover_cost: item.secp256k1_recover_cost,
|
||||
heap_size: item.heap_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
impl Default for BpfComputeBudget {
|
||||
fn default() -> Self {
|
||||
ComputeBudget::default().into()
|
||||
}
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
impl BpfComputeBudget {
|
||||
pub fn new() -> Self {
|
||||
BpfComputeBudget {
|
||||
max_units: 200_000,
|
||||
log_64_units: 100,
|
||||
create_program_address_units: 1500,
|
||||
invoke_units: 1000,
|
||||
max_invoke_depth: 4,
|
||||
sha256_base_cost: 85,
|
||||
sha256_byte_cost: 1,
|
||||
max_call_depth: 64,
|
||||
stack_frame_size: 4_096,
|
||||
log_pubkey_units: 100,
|
||||
max_cpi_instruction_size: 1280, // IPv6 Min MTU size
|
||||
cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
|
||||
sysvar_base_cost: 100,
|
||||
secp256k1_recover_cost: 25_000,
|
||||
heap_size: None,
|
||||
}
|
||||
BpfComputeBudget::default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,9 +374,12 @@ impl Logger for MockLogger {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub struct MockInvokeContext<'a> {
|
||||
pub invoke_stack: Vec<InvokeContextStackFrame<'a>>,
|
||||
pub logger: MockLogger,
|
||||
pub compute_budget: ComputeBudget,
|
||||
#[allow(deprecated)]
|
||||
pub bpf_compute_budget: BpfComputeBudget,
|
||||
pub compute_meter: MockComputeMeter,
|
||||
pub programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
||||
@ -348,11 +389,13 @@ pub struct MockInvokeContext<'a> {
|
||||
}
|
||||
impl<'a> MockInvokeContext<'a> {
|
||||
pub fn new(keyed_accounts: Vec<KeyedAccount<'a>>) -> Self {
|
||||
let bpf_compute_budget = BpfComputeBudget::default();
|
||||
let compute_budget = ComputeBudget::default();
|
||||
let mut invoke_context = MockInvokeContext {
|
||||
invoke_stack: Vec::with_capacity(bpf_compute_budget.max_invoke_depth),
|
||||
invoke_stack: Vec::with_capacity(compute_budget.max_invoke_depth),
|
||||
logger: MockLogger::default(),
|
||||
bpf_compute_budget,
|
||||
compute_budget,
|
||||
#[allow(deprecated)]
|
||||
bpf_compute_budget: compute_budget.into(),
|
||||
compute_meter: MockComputeMeter {
|
||||
remaining: std::i64::MAX as u64,
|
||||
},
|
||||
@ -442,7 +485,9 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
||||
Rc::new(RefCell::new(self.logger.clone()))
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
|
||||
#[allow(deprecated)]
|
||||
&self.bpf_compute_budget
|
||||
}
|
||||
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
|
||||
@ -477,4 +522,7 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||
.iter()
|
||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
||||
}
|
||||
fn get_compute_budget(&self) -> &ComputeBudget {
|
||||
&self.compute_budget
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user