Bump compute budget (#11864)

* Bump compute budget

* nudge
This commit is contained in:
Jack May
2020-08-26 14:48:51 -07:00
committed by GitHub
parent 5c7080c1f4
commit ea179ad762
7 changed files with 150 additions and 65 deletions

View File

@ -7,7 +7,7 @@ use solana_rbpf::EbpfVm;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
bpf_loader, bpf_loader,
entrypoint_native::{ComputeMeter, InvokeContext, Logger, ProcessInstruction}, entrypoint_native::{ComputeBudget, ComputeMeter, InvokeContext, Logger, ProcessInstruction},
instruction::{CompiledInstruction, InstructionError}, instruction::{CompiledInstruction, InstructionError},
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
@ -166,6 +166,9 @@ impl InvokeContext for MockInvokeContext {
fn is_cross_program_supported(&self) -> bool { fn is_cross_program_supported(&self) -> bool {
true true
} }
fn get_compute_budget(&self) -> ComputeBudget {
ComputeBudget::default()
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> { fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.mock_compute_meter.clone())) Rc::new(RefCell::new(self.mock_compute_meter.clone()))
} }

View File

@ -3,7 +3,7 @@ use solana_rbpf::ebpf;
use thiserror::Error; use thiserror::Error;
/// Error definitions /// Error definitions
#[derive(Debug, Error)] #[derive(Debug, Error, PartialEq)]
pub enum VerifierError { pub enum VerifierError {
/// ProgramLengthNotMultiple /// ProgramLengthNotMultiple
#[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)] #[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)]

View File

@ -50,7 +50,7 @@ impl<E> DecodeError<E> for BPFLoaderError {
} }
/// Errors returned by functions the BPF Loader registers with the vM /// Errors returned by functions the BPF Loader registers with the vM
#[derive(Debug, Error)] #[derive(Debug, Error, PartialEq)]
pub enum BPFError { pub enum BPFError {
#[error("{0}")] #[error("{0}")]
VerifierError(#[from] VerifierError), VerifierError(#[from] VerifierError),
@ -253,9 +253,10 @@ pub fn process_instruction(
mod tests { mod tests {
use super::*; use super::*;
use rand::Rng; use rand::Rng;
use solana_runtime::message_processor::ThisInvokeContext;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
entrypoint_native::{ComputeMeter, Logger, ProcessInstruction}, entrypoint_native::{ComputeBudget, Logger, ProcessInstruction},
instruction::CompiledInstruction, instruction::CompiledInstruction,
message::Message, message::Message,
rent::Rent, rent::Rent,
@ -332,6 +333,9 @@ mod tests {
fn is_cross_program_supported(&self) -> bool { fn is_cross_program_supported(&self) -> bool {
true true
} }
fn get_compute_budget(&self) -> ComputeBudget {
ComputeBudget::default()
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> { fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone())) Rc::new(RefCell::new(self.compute_meter.clone()))
} }
@ -562,6 +566,29 @@ mod tests {
) )
); );
// Case: limited budget
let program_id = Pubkey::default();
let mut invoke_context = ThisInvokeContext::new(
&program_id,
Rent::default(),
vec![],
vec![],
None,
true,
ComputeBudget {
max_units: 1,
log_units: 100,
log_64_units: 100,
create_program_address_units: 1500,
invoke_units: 1000,
max_invoke_depth: 2,
},
);
assert_eq!(
Err(InstructionError::Custom(194969602)),
process_instruction(&bpf_loader::id(), &keyed_accounts, &[], &mut invoke_context)
);
// Case: With duplicate accounts // Case: With duplicate accounts
let duplicate_key = Pubkey::new_rand(); let duplicate_key = Pubkey::new_rand();
let parameter_account = Account::new_ref(1, 0, &program_id); let parameter_account = Account::new_ref(1, 0, &program_id);

View File

@ -30,7 +30,7 @@ use std::{
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
/// Error definitions /// Error definitions
#[derive(Debug, ThisError)] #[derive(Debug, ThisError, PartialEq)]
pub enum SyscallError { pub enum SyscallError {
#[error("{0}: {1:?}")] #[error("{0}: {1:?}")]
InvalidString(Utf8Error, Vec<u8>), InvalidString(Utf8Error, Vec<u8>),
@ -59,13 +59,6 @@ impl From<SyscallError> for EbpfError<BPFError> {
} }
} }
/// Sysval compute costs
/// Note: `abort`, `sol_panic_`, and `sol_alloc_free_` do not currently incur a cost
const COMPUTE_COST_LOG: u64 = 100;
const COMPUTE_COST_LOG_64: u64 = 100;
const COMPUTE_COST_CREATE_PROGRAM_ADDRESS: u64 = 1000;
const COMPUTE_COST_INVOKE: u64 = 1000;
trait SyscallConsume { trait SyscallConsume {
fn consume(&mut self, amount: u64) -> Result<(), EbpfError<BPFError>>; fn consume(&mut self, amount: u64) -> Result<(), EbpfError<BPFError>>;
} }
@ -97,6 +90,7 @@ pub fn register_syscalls<'a>(
callers_keyed_accounts: &'a [KeyedAccount<'a>], callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext, invoke_context: &'a mut dyn InvokeContext,
) -> Result<MemoryRegion, EbpfError<BPFError>> { ) -> Result<MemoryRegion, EbpfError<BPFError>> {
let compute_budget = invoke_context.get_compute_budget();
// Syscall functions common across languages // Syscall functions common across languages
vm.register_syscall_ex("abort", syscall_abort)?; vm.register_syscall_ex("abort", syscall_abort)?;
@ -104,6 +98,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_log_", "sol_log_",
Box::new(SyscallLog { Box::new(SyscallLog {
cost: compute_budget.log_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
}), }),
@ -111,6 +106,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_log_64_", "sol_log_64_",
Box::new(SyscallLogU64 { Box::new(SyscallLogU64 {
cost: compute_budget.log_64_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
}), }),
@ -119,6 +115,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_create_program_address", "sol_create_program_address",
Box::new(SyscallCreateProgramAddress { Box::new(SyscallCreateProgramAddress {
cost: compute_budget.create_program_address_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
}), }),
)?; )?;
@ -282,6 +279,7 @@ pub fn syscall_sol_panic(
/// Log a user's info message /// Log a user's info message
pub struct SyscallLog { pub struct SyscallLog {
cost: u64,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
} }
@ -296,7 +294,7 @@ impl SyscallObject<BPFError> for SyscallLog {
ro_regions: &[MemoryRegion], ro_regions: &[MemoryRegion],
_rw_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> { ) -> Result<u64, EbpfError<BPFError>> {
self.compute_meter.consume(COMPUTE_COST_LOG)?; self.compute_meter.consume(self.cost)?;
let mut logger = self let mut logger = self
.logger .logger
.try_borrow_mut() .try_borrow_mut()
@ -313,6 +311,7 @@ impl SyscallObject<BPFError> for SyscallLog {
/// Log 5 64-bit values /// Log 5 64-bit values
pub struct SyscallLogU64 { pub struct SyscallLogU64 {
cost: u64,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
} }
@ -327,7 +326,7 @@ impl SyscallObject<BPFError> for SyscallLogU64 {
_ro_regions: &[MemoryRegion], _ro_regions: &[MemoryRegion],
_rw_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> { ) -> Result<u64, EbpfError<BPFError>> {
self.compute_meter.consume(COMPUTE_COST_LOG_64)?; self.compute_meter.consume(self.cost)?;
let mut logger = self let mut logger = self
.logger .logger
.try_borrow_mut() .try_borrow_mut()
@ -386,6 +385,7 @@ impl SyscallObject<BPFError> for SyscallSolAllocFree {
/// Create a program address /// Create a program address
pub struct SyscallCreateProgramAddress { pub struct SyscallCreateProgramAddress {
cost: u64,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
} }
impl SyscallObject<BPFError> for SyscallCreateProgramAddress { impl SyscallObject<BPFError> for SyscallCreateProgramAddress {
@ -399,8 +399,7 @@ impl SyscallObject<BPFError> for SyscallCreateProgramAddress {
ro_regions: &[MemoryRegion], ro_regions: &[MemoryRegion],
rw_regions: &[MemoryRegion], rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> { ) -> Result<u64, EbpfError<BPFError>> {
self.compute_meter self.compute_meter.consume(self.cost)?;
.consume(COMPUTE_COST_CREATE_PROGRAM_ADDRESS)?;
let untranslated_seeds = translate_slice!(&[&u8], seeds_addr, seeds_len, ro_regions)?; let untranslated_seeds = translate_slice!(&[&u8], seeds_addr, seeds_len, ro_regions)?;
let seeds = untranslated_seeds let seeds = untranslated_seeds
@ -894,7 +893,7 @@ fn call<'a>(
let mut invoke_context = syscall.get_context_mut()?; let mut invoke_context = syscall.get_context_mut()?;
invoke_context invoke_context
.get_compute_meter() .get_compute_meter()
.consume(COMPUTE_COST_INVOKE)?; .consume(invoke_context.get_compute_budget().invoke_units)?;
// Translate data passed from the VM // Translate data passed from the VM
@ -1134,13 +1133,12 @@ mod tests {
let addr = string.as_ptr() as *const _ as u64; let addr = string.as_ptr() as *const _ as u64;
let compute_meter: Rc<RefCell<dyn ComputeMeter>> = let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
Rc::new(RefCell::new(MockComputeMeter { Rc::new(RefCell::new(MockComputeMeter { remaining: 3 }));
remaining: std::u64::MAX, // TODO also test error
}));
let log = Rc::new(RefCell::new(vec![])); let log = Rc::new(RefCell::new(vec![]));
let logger: Rc<RefCell<dyn Logger>> = let logger: Rc<RefCell<dyn Logger>> =
Rc::new(RefCell::new(MockLogger { log: log.clone() })); Rc::new(RefCell::new(MockLogger { log: log.clone() }));
let mut syscall_sol_log = SyscallLog { let mut syscall_sol_log = SyscallLog {
cost: 1,
compute_meter, compute_meter,
logger, logger,
}; };
@ -1155,8 +1153,15 @@ mod tests {
.call(100, string.len() as u64, 0, 0, 0, ro_regions, rw_regions) .call(100, string.len() as u64, 0, 0, 0, ro_regions, rw_regions)
.unwrap(); .unwrap();
syscall_sol_log assert_eq!(
.call( Err(EbpfError::AccessViolation(
"programs/bpf_loader/src/syscalls.rs".to_string(),
238,
100,
32,
" regions: \n0x64-0x73".to_string()
)),
syscall_sol_log.call(
100, 100,
string.len() as u64 * 2, // AccessViolation string.len() as u64 * 2, // AccessViolation
0, 0,
@ -1165,7 +1170,22 @@ mod tests {
ro_regions, ro_regions,
rw_regions, rw_regions,
) )
.unwrap_err(); );
assert_eq!(
Err(EbpfError::UserError(BPFError::SyscallError(
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
))),
syscall_sol_log.call(
100,
string.len() as u64 * 2, // AccessViolation
0,
0,
0,
ro_regions,
rw_regions,
)
);
assert_eq!(log.borrow().len(), 1); assert_eq!(log.borrow().len(), 1);
assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!"); assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!");
@ -1175,12 +1195,13 @@ mod tests {
fn test_syscall_sol_log_u64() { fn test_syscall_sol_log_u64() {
let compute_meter: Rc<RefCell<dyn ComputeMeter>> = let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
Rc::new(RefCell::new(MockComputeMeter { Rc::new(RefCell::new(MockComputeMeter {
remaining: std::u64::MAX, // TODO also test error remaining: std::u64::MAX,
})); }));
let log = Rc::new(RefCell::new(vec![])); let log = Rc::new(RefCell::new(vec![]));
let logger: Rc<RefCell<dyn Logger>> = let logger: Rc<RefCell<dyn Logger>> =
Rc::new(RefCell::new(MockLogger { log: log.clone() })); Rc::new(RefCell::new(MockLogger { log: log.clone() }));
let mut syscall_sol_log_u64 = SyscallLogU64 { let mut syscall_sol_log_u64 = SyscallLogU64 {
cost: 0,
compute_meter, compute_meter,
logger, logger,
}; };

View File

@ -13,7 +13,7 @@ use crate::{
builtins::get_builtins, builtins::get_builtins,
epoch_stakes::{EpochStakes, NodeVoteAccounts}, epoch_stakes::{EpochStakes, NodeVoteAccounts},
log_collector::LogCollector, log_collector::LogCollector,
message_processor::{MessageProcessor, DEFAULT_COMPUTE_BUDGET, DEFAULT_MAX_INVOKE_DEPTH}, message_processor::MessageProcessor,
nonce_utils, nonce_utils,
rent_collector::RentCollector, rent_collector::RentCollector,
stakes::Stakes, stakes::Stakes,
@ -35,7 +35,7 @@ use solana_sdk::{
Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
}, },
entrypoint_native::{ProcessInstruction, ProcessInstructionWithContext}, entrypoint_native::{ComputeBudget, ProcessInstruction, ProcessInstructionWithContext},
epoch_info::EpochInfo, epoch_info::EpochInfo,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::{FeeCalculator, FeeRateGovernor}, fee_calculator::{FeeCalculator, FeeRateGovernor},
@ -1245,13 +1245,8 @@ impl Bank {
.set_cross_program_support(is_supported); .set_cross_program_support(is_supported);
} }
pub fn set_max_invoke_depth(&mut self, max_invoke_depth: usize) { pub fn set_compute_budget(&mut self, budget: ComputeBudget) {
self.message_processor self.message_processor.set_compute_budget(budget);
.set_max_invoke_depth(max_invoke_depth);
}
pub fn set_compute_budget(&mut self, compute_units: u64) {
self.message_processor.set_compute_budget(compute_units);
} }
/// Return the last block hash registered. /// Return the last block hash registered.
@ -3210,8 +3205,7 @@ impl Bank {
self.ensure_builtins(init_finish_or_warp); self.ensure_builtins(init_finish_or_warp);
self.reinvoke_entered_epoch_callback(initiate_callback); self.reinvoke_entered_epoch_callback(initiate_callback);
self.recheck_cross_program_support(); self.recheck_cross_program_support();
self.set_max_invoke_depth(DEFAULT_MAX_INVOKE_DEPTH); self.recheck_compute_budget();
self.set_compute_budget(DEFAULT_COMPUTE_BUDGET);
} }
fn ensure_builtins(&mut self, init_or_warp: bool) { fn ensure_builtins(&mut self, init_or_warp: bool) {
@ -3240,6 +3234,27 @@ impl Bank {
} }
} }
fn recheck_compute_budget(self: &mut Bank) {
let compute_budget = if OperatingMode::Stable == self.operating_mode() {
if self.epoch() >= u64::MAX - 1 {
ComputeBudget::default()
} else {
// Original
ComputeBudget {
max_units: 100_000,
log_units: 0,
log_64_units: 0,
create_program_address_units: 0,
invoke_units: 0,
max_invoke_depth: 2,
}
}
} else {
ComputeBudget::default()
};
self.set_compute_budget(compute_budget);
}
fn fix_recent_blockhashes_sysvar_delay(&self) -> bool { fn fix_recent_blockhashes_sysvar_delay(&self) -> bool {
let activation_slot = match self.operating_mode() { let activation_slot = match self.operating_mode() {
OperatingMode::Development => 0, OperatingMode::Development => 0,

View File

@ -7,8 +7,8 @@ use solana_sdk::{
account::{create_keyed_readonly_accounts, Account, KeyedAccount}, account::{create_keyed_readonly_accounts, Account, KeyedAccount},
clock::Epoch, clock::Epoch,
entrypoint_native::{ entrypoint_native::{
ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext, InvokeContext, ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
Logger, ProcessInstruction, ProcessInstructionWithContext, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
}, },
instruction::{CompiledInstruction, InstructionError}, instruction::{CompiledInstruction, InstructionError},
message::Message, message::Message,
@ -20,9 +20,6 @@ use solana_sdk::{
}; };
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub const DEFAULT_MAX_INVOKE_DEPTH: usize = 2;
pub const DEFAULT_COMPUTE_BUDGET: u64 = 100_000;
// The relevant state of an account before an Instruction executes, used // The relevant state of an account before an Instruction executes, used
// to verify account integrity after the Instruction completes // to verify account integrity after the Instruction completes
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -183,7 +180,7 @@ pub struct ThisInvokeContext {
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
is_cross_program_supported: bool, is_cross_program_supported: bool,
max_invoke_depth: usize, compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
} }
impl ThisInvokeContext { impl ThisInvokeContext {
@ -194,10 +191,9 @@ impl ThisInvokeContext {
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
is_cross_program_supported: bool, is_cross_program_supported: bool,
max_invoke_depth: usize, compute_budget: ComputeBudget,
compute_budget: u64,
) -> Self { ) -> Self {
let mut program_ids = Vec::with_capacity(max_invoke_depth); let mut program_ids = Vec::with_capacity(compute_budget.max_invoke_depth);
program_ids.push(*program_id); program_ids.push(*program_id);
Self { Self {
program_ids, program_ids,
@ -206,16 +202,16 @@ impl ThisInvokeContext {
programs, programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })), logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
is_cross_program_supported, is_cross_program_supported,
max_invoke_depth, compute_budget,
compute_meter: Rc::new(RefCell::new(ThisComputeMeter { compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
remaining: compute_budget, remaining: compute_budget.max_units,
})), })),
} }
} }
} }
impl InvokeContext for ThisInvokeContext { impl InvokeContext for ThisInvokeContext {
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> { fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
if self.program_ids.len() >= self.max_invoke_depth { if self.program_ids.len() >= self.compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth); return Err(InstructionError::CallDepth);
} }
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) { if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
@ -260,6 +256,9 @@ impl InvokeContext for ThisInvokeContext {
fn is_cross_program_supported(&self) -> bool { fn is_cross_program_supported(&self) -> bool {
self.is_cross_program_supported self.is_cross_program_supported
} }
fn get_compute_budget(&self) -> ComputeBudget {
self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> { fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
self.compute_meter.clone() self.compute_meter.clone()
} }
@ -290,9 +289,7 @@ pub struct MessageProcessor {
#[serde(skip)] #[serde(skip)]
is_cross_program_supported: bool, is_cross_program_supported: bool,
#[serde(skip)] #[serde(skip)]
max_invoke_depth: usize, compute_budget: ComputeBudget,
#[serde(skip)]
compute_budget: u64,
} }
impl std::fmt::Debug for MessageProcessor { impl std::fmt::Debug for MessageProcessor {
@ -339,11 +336,7 @@ impl Default for MessageProcessor {
loaders: vec![], loaders: vec![],
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
is_cross_program_supported: true, is_cross_program_supported: true,
// Maximum cross-program invocation depth allowed including the orignal caller compute_budget: ComputeBudget::default(),
max_invoke_depth: DEFAULT_MAX_INVOKE_DEPTH,
// Number of compute units that an instruction is allowed. Compute units
// are consumed by program execution, resources they use, etc...
compute_budget: DEFAULT_COMPUTE_BUDGET,
} }
} }
} }
@ -391,11 +384,7 @@ impl MessageProcessor {
self.is_cross_program_supported = is_supported; self.is_cross_program_supported = is_supported;
} }
pub fn set_max_invoke_depth(&mut self, max_invoke_depth: usize) { pub fn set_compute_budget(&mut self, compute_budget: ComputeBudget) {
self.max_invoke_depth = max_invoke_depth;
}
pub fn set_compute_budget(&mut self, compute_budget: u64) {
self.compute_budget = compute_budget; self.compute_budget = compute_budget;
} }
@ -651,7 +640,6 @@ impl MessageProcessor {
self.programs.clone(), // get rid of clone self.programs.clone(), // get rid of clone
log_collector, log_collector,
self.is_cross_program_supported, self.is_cross_program_supported,
self.max_invoke_depth,
self.compute_budget, self.compute_budget,
); );
let keyed_accounts = let keyed_accounts =
@ -742,8 +730,7 @@ mod tests {
vec![], vec![],
None, None,
true, true,
DEFAULT_MAX_INVOKE_DEPTH, ComputeBudget::default(),
DEFAULT_COMPUTE_BUDGET,
); );
// Check call depth increases and has a limit // Check call depth increases and has a limit
@ -1514,8 +1501,7 @@ mod tests {
vec![], vec![],
None, None,
true, true,
DEFAULT_MAX_INVOKE_DEPTH, ComputeBudget::default(),
DEFAULT_COMPUTE_BUDGET,
); );
let metas = vec![ let metas = vec![
AccountMeta::new(owned_key, false), AccountMeta::new(owned_key, false),

View File

@ -210,10 +210,43 @@ pub trait InvokeContext {
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>; fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
/// Are cross program invocations supported /// Are cross program invocations supported
fn is_cross_program_supported(&self) -> bool; fn is_cross_program_supported(&self) -> bool;
/// Get this invocation's compute budget
fn get_compute_budget(&self) -> ComputeBudget;
/// Get this invocation's compute meter /// Get this invocation's compute meter
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>; fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
} }
#[derive(Clone, Copy, Debug)]
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 call
pub log_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 incured by
/// the called program)
pub invoke_units: u64,
/// Maximum cross-program invocation depth allowed including the orignal caller
pub max_invoke_depth: usize,
}
impl Default for ComputeBudget {
fn default() -> Self {
// Tuned for ~1ms
ComputeBudget {
max_units: 200_000,
log_units: 100,
log_64_units: 100,
create_program_address_units: 1500,
invoke_units: 1000,
max_invoke_depth: 2,
}
}
}
/// Compute meter /// Compute meter
pub trait ComputeMeter { pub trait ComputeMeter {
/// Consume compute units /// Consume compute units