Pipe FeatureSet though InvokeContext (#12536)

* Pipe FeatureSet though InvokeContext

* gate program size cap

* nit
This commit is contained in:
Jack May 2020-09-29 14:36:30 -07:00 committed by GitHub
parent ce98088457
commit 74fcb184b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 124 additions and 180 deletions

View File

@ -218,7 +218,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
"Tuner must consume the whole budget" "Tuner must consume the whole budget"
); );
println!( println!(
"{:?} Consumed compute budget took {:?} us ({:?} instructions)", "{:?} compute units took {:?} us ({:?} instructions)",
BUDGET - instruction_meter.get_remaining(), BUDGET - instruction_meter.get_remaining(),
measure.as_us(), measure.as_us(),
vm.get_total_instruction_count(), vm.get_total_instruction_count(),
@ -229,6 +229,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
pub struct MockInvokeContext { pub struct MockInvokeContext {
key: Pubkey, key: Pubkey,
logger: MockLogger, logger: MockLogger,
compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<MockComputeMeter>>, compute_meter: Rc<RefCell<MockComputeMeter>>,
} }
impl InvokeContext for MockInvokeContext { impl InvokeContext for MockInvokeContext {
@ -253,11 +254,8 @@ impl InvokeContext for MockInvokeContext {
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> { fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone())) Rc::new(RefCell::new(self.logger.clone()))
} }
fn is_cross_program_supported(&self) -> bool { fn get_compute_budget(&self) -> &ComputeBudget {
true &self.compute_budget
}
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>> {
self.compute_meter.clone() self.compute_meter.clone()
@ -267,6 +265,9 @@ impl InvokeContext for MockInvokeContext {
None None
} }
fn record_instruction(&self, _instruction: &Instruction) {} fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct MockLogger { pub struct MockLogger {

View File

@ -23,7 +23,6 @@ use solana_sdk::{
client::SyncClient, client::SyncClient,
clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE}, clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE},
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
@ -657,6 +656,7 @@ fn assert_instruction_count() {
struct MockInvokeContext { struct MockInvokeContext {
pub key: Pubkey, pub key: Pubkey,
pub logger: MockLogger, pub logger: MockLogger,
pub compute_budget: ComputeBudget,
pub compute_meter: MockComputeMeter, pub compute_meter: MockComputeMeter,
} }
impl InvokeContext for MockInvokeContext { impl InvokeContext for MockInvokeContext {
@ -681,11 +681,8 @@ impl InvokeContext for MockInvokeContext {
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> { fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone())) Rc::new(RefCell::new(self.logger.clone()))
} }
fn is_cross_program_supported(&self) -> bool { fn get_compute_budget(&self) -> &ComputeBudget {
true &self.compute_budget
}
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()))
@ -695,6 +692,9 @@ impl InvokeContext for MockInvokeContext {
None None
} }
fn record_instruction(&self, _instruction: &Instruction) {} fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]

View File

@ -54,11 +54,11 @@ pub enum VerifierError {
InvalidRegister(usize), InvalidRegister(usize),
} }
fn check_prog_len(prog: &[u8]) -> Result<(), BPFError> { fn check_prog_len(prog: &[u8], is_program_size_cap: bool) -> Result<(), BPFError> {
if prog.len() % ebpf::INSN_SIZE != 0 { if prog.len() % ebpf::INSN_SIZE != 0 {
return Err(VerifierError::ProgramLengthNotMultiple.into()); return Err(VerifierError::ProgramLengthNotMultiple.into());
} }
if prog.len() > ebpf::PROG_MAX_SIZE { if is_program_size_cap && prog.len() > ebpf::PROG_MAX_SIZE {
return Err(VerifierError::ProgramTooLarge(prog.len() / ebpf::INSN_SIZE).into()); return Err(VerifierError::ProgramTooLarge(prog.len() / ebpf::INSN_SIZE).into());
} }
@ -139,8 +139,8 @@ fn check_imm_register(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Verifier
} }
#[rustfmt::skip] #[rustfmt::skip]
pub fn check(prog: &[u8]) -> Result<(), BPFError> { pub fn check(prog: &[u8], is_program_size_cap: bool) -> Result<(), BPFError> {
check_prog_len(prog)?; check_prog_len(prog, is_program_size_cap)?;
let mut insn_ptr: usize = 0; let mut insn_ptr: usize = 0;
while insn_ptr * ebpf::INSN_SIZE < prog.len() { while insn_ptr * ebpf::INSN_SIZE < prog.len() {

View File

@ -16,7 +16,10 @@ use solana_rbpf::{
memory_region::MemoryRegion, memory_region::MemoryRegion,
vm::{EbpfVm, Executable, InstructionMeter}, vm::{EbpfVm, Executable, InstructionMeter},
}; };
use solana_runtime::process_instruction::{ComputeMeter, Executor, InvokeContext}; use solana_runtime::{
feature_set::compute_budget_config2,
process_instruction::{ComputeMeter, Executor, InvokeContext},
};
use solana_sdk::{ use solana_sdk::{
account::{is_executable, next_keyed_account, KeyedAccount}, account::{is_executable, next_keyed_account, KeyedAccount},
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
@ -78,19 +81,29 @@ macro_rules! log{
}; };
} }
fn map_ebpf_error(
invoke_context: &mut dyn InvokeContext,
e: EbpfError<BPFError>,
) -> InstructionError {
let logger = invoke_context.get_logger();
log!(logger, "{}", e);
InstructionError::InvalidAccountData
}
pub fn create_and_cache_executor( pub fn create_and_cache_executor(
program: &KeyedAccount, program: &KeyedAccount,
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<Arc<BPFExecutor>, InstructionError> { ) -> Result<Arc<BPFExecutor>, InstructionError> {
let executable = EbpfVm::create_executable_from_elf( let executable = EbpfVm::create_executable_from_elf(&program.try_account_ref()?.data, None)
&program.try_account_ref()?.data, .map_err(|e| map_ebpf_error(invoke_context, e))?;
Some(bpf_verifier::check), let (_, elf_bytes) = executable
.get_text_bytes()
.map_err(|e| map_ebpf_error(invoke_context, e))?;
bpf_verifier::check(
elf_bytes,
!invoke_context.is_feature_active(&compute_budget_config2::id()),
) )
.map_err(|e| { .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
let logger = invoke_context.get_logger();
log!(logger, "{}", e);
InstructionError::InvalidAccountData
})?;
let executor = Arc::new(BPFExecutor { executable }); let executor = Arc::new(BPFExecutor { executable });
invoke_context.add_executor(program.unsigned_key(), executor.clone()); invoke_context.add_executor(program.unsigned_key(), executor.clone());
Ok(executor) Ok(executor)
@ -271,6 +284,7 @@ mod tests {
use super::*; use super::*;
use rand::Rng; use rand::Rng;
use solana_runtime::{ use solana_runtime::{
feature_set::FeatureSet,
message_processor::{Executors, ThisInvokeContext}, message_processor::{Executors, ThisInvokeContext},
process_instruction::{ComputeBudget, Logger, ProcessInstruction}, process_instruction::{ComputeBudget, Logger, ProcessInstruction},
}; };
@ -313,6 +327,7 @@ mod tests {
pub struct MockInvokeContext { pub struct MockInvokeContext {
pub key: Pubkey, pub key: Pubkey,
pub logger: MockLogger, pub logger: MockLogger,
pub compute_budget: ComputeBudget,
pub compute_meter: MockComputeMeter, pub compute_meter: MockComputeMeter,
} }
impl Default for MockInvokeContext { impl Default for MockInvokeContext {
@ -320,6 +335,7 @@ mod tests {
MockInvokeContext { MockInvokeContext {
key: Pubkey::default(), key: Pubkey::default(),
logger: MockLogger::default(), logger: MockLogger::default(),
compute_budget: ComputeBudget::default(),
compute_meter: MockComputeMeter { compute_meter: MockComputeMeter {
remaining: std::u64::MAX, remaining: std::u64::MAX,
}, },
@ -348,11 +364,8 @@ mod tests {
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> { fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone())) Rc::new(RefCell::new(self.logger.clone()))
} }
fn is_cross_program_supported(&self) -> bool { fn get_compute_budget(&self) -> &ComputeBudget {
true &self.compute_budget
}
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()))
@ -362,6 +375,9 @@ mod tests {
None None
} }
fn record_instruction(&self, _instruction: &Instruction) {} fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
} }
struct TestInstructionMeter { struct TestInstructionMeter {
@ -387,8 +403,7 @@ mod tests {
]; ];
let input = &mut [0x00]; let input = &mut [0x00];
let executable = let executable = EbpfVm::create_executable_from_text_bytes(program, None).unwrap();
EbpfVm::create_executable_from_text_bytes(program, Some(bpf_verifier::check)).unwrap();
let mut vm = EbpfVm::<BPFError>::new(executable.as_ref()).unwrap(); let mut vm = EbpfVm::<BPFError>::new(executable.as_ref()).unwrap();
let instruction_meter = TestInstructionMeter { remaining: 10 }; let instruction_meter = TestInstructionMeter { remaining: 10 };
vm.execute_program_metered(input, &[], &[], instruction_meter) vm.execute_program_metered(input, &[], &[], instruction_meter)
@ -579,7 +594,6 @@ mod tests {
vec![], vec![],
vec![], vec![],
None, None,
true,
ComputeBudget { ComputeBudget {
max_units: 1, max_units: 1,
log_units: 100, log_units: 100,
@ -590,6 +604,7 @@ mod tests {
}, },
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,
Arc::new(FeatureSet::default()),
); );
assert_eq!( assert_eq!(
Err(InstructionError::Custom(194969602)), Err(InstructionError::Custom(194969602)),

View File

@ -94,6 +94,7 @@ pub fn register_syscalls<'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(); 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)?;
@ -115,36 +116,35 @@ pub fn register_syscalls<'a>(
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
}), }),
)?; )?;
if invoke_context.is_cross_program_supported() {
vm.register_syscall_with_context_ex(
"sol_create_program_address",
Box::new(SyscallCreateProgramAddress {
cost: compute_budget.create_program_address_units,
compute_meter: invoke_context.get_compute_meter(),
loader_id,
}),
)?;
// Cross-program invocation syscalls vm.register_syscall_with_context_ex(
"sol_create_program_address",
Box::new(SyscallCreateProgramAddress {
cost: compute_budget.create_program_address_units,
compute_meter: invoke_context.get_compute_meter(),
loader_id,
}),
)?;
let invoke_context = Rc::new(RefCell::new(invoke_context)); // Cross-program invocation syscalls
vm.register_syscall_with_context_ex(
"sol_invoke_signed_c", let invoke_context = Rc::new(RefCell::new(invoke_context));
Box::new(SyscallInvokeSignedC { vm.register_syscall_with_context_ex(
callers_keyed_accounts, "sol_invoke_signed_c",
invoke_context: invoke_context.clone(), Box::new(SyscallInvokeSignedC {
loader_id, callers_keyed_accounts,
}), invoke_context: invoke_context.clone(),
)?; loader_id,
vm.register_syscall_with_context_ex( }),
"sol_invoke_signed_rust", )?;
Box::new(SyscallInvokeSignedRust { vm.register_syscall_with_context_ex(
callers_keyed_accounts, "sol_invoke_signed_rust",
invoke_context: invoke_context.clone(), Box::new(SyscallInvokeSignedRust {
loader_id, callers_keyed_accounts,
}), invoke_context: invoke_context.clone(),
)?; loader_id,
} }),
)?;
// Memory allocator // Memory allocator
let heap = vec![0_u8; DEFAULT_HEAP_SIZE]; let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
@ -1044,7 +1044,6 @@ fn call<'a>(
} }
message_processor.add_loader(bpf_loader::id(), crate::process_instruction); message_processor.add_loader(bpf_loader::id(), crate::process_instruction);
message_processor.add_loader(bpf_loader_deprecated::id(), crate::process_instruction); message_processor.add_loader(bpf_loader_deprecated::id(), crate::process_instruction);
message_processor.set_cross_program_support(invoke_context.is_cross_program_supported());
#[allow(clippy::deref_addrof)] #[allow(clippy::deref_addrof)]
match message_processor.process_cross_program_instruction( match message_processor.process_cross_program_instruction(

View File

@ -18,9 +18,7 @@ use crate::{
log_collector::LogCollector, log_collector::LogCollector,
message_processor::{Executors, MessageProcessor}, message_processor::{Executors, MessageProcessor},
nonce_utils, nonce_utils,
process_instruction::{ process_instruction::{Executor, ProcessInstruction, ProcessInstructionWithContext},
ComputeBudget, Executor, ProcessInstruction, ProcessInstructionWithContext,
},
rent_collector::RentCollector, rent_collector::RentCollector,
stakes::Stakes, stakes::Stakes,
status_cache::{SlotDelta, StatusCache}, status_cache::{SlotDelta, StatusCache},
@ -1476,15 +1474,6 @@ impl Bank {
debug!("Added native program {} under {:?}", name, program_id); debug!("Added native program {} under {:?}", name, program_id);
} }
pub fn set_cross_program_support(&mut self, is_supported: bool) {
self.message_processor
.set_cross_program_support(is_supported);
}
pub fn set_compute_budget(&mut self, budget: ComputeBudget) {
self.message_processor.set_compute_budget(budget);
}
pub fn set_rent_burn_percentage(&mut self, burn_percent: u8) { pub fn set_rent_burn_percentage(&mut self, burn_percent: u8) {
self.rent_collector.rent.burn_percent = burn_percent; self.rent_collector.rent.burn_percent = burn_percent;
} }
@ -2155,7 +2144,7 @@ impl Bank {
log_collector.clone(), log_collector.clone(),
executors.clone(), executors.clone(),
instruction_recorders.as_deref(), instruction_recorders.as_deref(),
&self.feature_set, self.feature_set.clone(),
); );
Self::compile_recorded_instructions( Self::compile_recorded_instructions(
@ -3610,8 +3599,6 @@ impl Bank {
} }
self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations); self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations);
self.recheck_cross_program_support();
self.recheck_compute_budget();
self.reconfigure_token2_native_mint(); self.reconfigure_token2_native_mint();
self.ensure_no_storage_rewards_pool(); self.ensure_no_storage_rewards_pool();
} }
@ -3675,35 +3662,6 @@ impl Bank {
} }
} }
fn recheck_cross_program_support(&mut self) {
if ClusterType::MainnetBeta == self.cluster_type() {
self.set_cross_program_support(self.epoch() >= 63);
} else {
self.set_cross_program_support(true);
}
}
fn recheck_compute_budget(&mut self) {
let compute_budget = if ClusterType::MainnetBeta == self.cluster_type() {
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 apply_spl_token_v2_multisig_fix(&mut self) { fn apply_spl_token_v2_multisig_fix(&mut self) {
if let Some(mut account) = self.get_account(&inline_spl_token_v2_0::id()) { if let Some(mut account) = self.get_account(&inline_spl_token_v2_0::id()) {
self.capitalization.fetch_sub(account.lamports, Relaxed); self.capitalization.fetch_sub(account.lamports, Relaxed);
@ -8701,19 +8659,6 @@ mod tests {
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 496); // no transaction fee charged assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 496); // no transaction fee charged
} }
#[test]
fn test_finish_init() {
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
let mut bank = Bank::new(&genesis_config);
bank.message_processor = MessageProcessor::default();
bank.message_processor.set_cross_program_support(false);
// simulate bank is just after deserialized from snapshot
bank.finish_init(&genesis_config, None);
assert_eq!(bank.message_processor.get_cross_program_support(), true);
}
#[test] #[test]
fn test_add_builtin_program_no_overwrite() { fn test_add_builtin_program_no_overwrite() {
let (genesis_config, _mint_keypair) = create_genesis_config(100_000); let (genesis_config, _mint_keypair) = create_genesis_config(100_000);

View File

@ -29,6 +29,10 @@ pub mod bpf_loader2_program {
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD"); solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
} }
pub mod compute_budget_config2 {
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
}
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> = [
@ -38,6 +42,7 @@ lazy_static! {
(pico_inflation::id(), "pico-inflation"), (pico_inflation::id(), "pico-inflation"),
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
(bpf_loader2_program::id(), "bpf_loader2 program"), (bpf_loader2_program::id(), "bpf_loader2 program"),
(compute_budget_config2::id(), "1ms compute budget"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()
@ -78,12 +83,3 @@ impl Default for FeatureSet {
} }
} }
} }
impl FeatureSet {
pub fn enabled() -> Self {
Self {
active: FEATURE_NAMES.keys().cloned().collect(),
inactive: HashSet::new(),
}
}
}

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
feature_set::{self, FeatureSet}, feature_set::{compute_budget_config2, instructions_sysvar_enabled, FeatureSet},
instruction_recorder::InstructionRecorder, instruction_recorder::InstructionRecorder,
log_collector::LogCollector, log_collector::LogCollector,
native_loader::NativeLoader, native_loader::NativeLoader,
@ -206,11 +206,11 @@ pub struct ThisInvokeContext {
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
is_cross_program_supported: bool,
compute_budget: ComputeBudget, compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>,
} }
impl ThisInvokeContext { impl ThisInvokeContext {
pub fn new( pub fn new(
@ -219,10 +219,10 @@ impl ThisInvokeContext {
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
is_cross_program_supported: bool,
compute_budget: ComputeBudget, compute_budget: ComputeBudget,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>,
) -> Self { ) -> Self {
let mut program_ids = Vec::with_capacity(compute_budget.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);
@ -232,13 +232,13 @@ impl ThisInvokeContext {
pre_accounts, pre_accounts,
programs, programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })), logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
is_cross_program_supported,
compute_budget, compute_budget,
compute_meter: Rc::new(RefCell::new(ThisComputeMeter { compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
remaining: compute_budget.max_units, remaining: compute_budget.max_units,
})), })),
executors, executors,
instruction_recorder, instruction_recorder,
feature_set,
} }
} }
} }
@ -286,11 +286,8 @@ impl InvokeContext for ThisInvokeContext {
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> { fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
self.logger.clone() self.logger.clone()
} }
fn is_cross_program_supported(&self) -> bool { fn get_compute_budget(&self) -> &ComputeBudget {
self.is_cross_program_supported &self.compute_budget
}
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()
@ -306,6 +303,9 @@ impl InvokeContext for ThisInvokeContext {
recorder.record_instruction(instruction.clone()); recorder.record_instruction(instruction.clone());
} }
} }
fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
self.feature_set.is_active(feature_id)
}
} }
pub struct ThisLogger { pub struct ThisLogger {
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
@ -330,10 +330,6 @@ pub struct MessageProcessor {
loaders: Vec<(Pubkey, ProcessInstructionWithContext)>, loaders: Vec<(Pubkey, ProcessInstructionWithContext)>,
#[serde(skip)] #[serde(skip)]
native_loader: NativeLoader, native_loader: NativeLoader,
#[serde(skip)]
is_cross_program_supported: bool,
#[serde(skip)]
compute_budget: ComputeBudget,
} }
impl std::fmt::Debug for MessageProcessor { impl std::fmt::Debug for MessageProcessor {
@ -343,8 +339,6 @@ impl std::fmt::Debug for MessageProcessor {
programs: Vec<String>, programs: Vec<String>,
loaders: Vec<String>, loaders: Vec<String>,
native_loader: &'a NativeLoader, native_loader: &'a NativeLoader,
is_cross_program_supported: bool,
compute_budget: ComputeBudget,
} }
// rustc doesn't compile due to bug without this work around // rustc doesn't compile due to bug without this work around
// https://github.com/rust-lang/rust/issues/50280 // https://github.com/rust-lang/rust/issues/50280
@ -367,8 +361,6 @@ impl std::fmt::Debug for MessageProcessor {
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
native_loader: &self.native_loader, native_loader: &self.native_loader,
is_cross_program_supported: self.is_cross_program_supported,
compute_budget: self.compute_budget,
}; };
write!(f, "{:?}", processor) write!(f, "{:?}", processor)
@ -381,8 +373,6 @@ impl Default for MessageProcessor {
programs: vec![], programs: vec![],
loaders: vec![], loaders: vec![],
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
is_cross_program_supported: true,
compute_budget: ComputeBudget::default(),
} }
} }
} }
@ -392,7 +382,6 @@ impl Clone for MessageProcessor {
programs: self.programs.clone(), programs: self.programs.clone(),
loaders: self.loaders.clone(), loaders: self.loaders.clone(),
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
..*self
} }
} }
} }
@ -426,17 +415,20 @@ impl MessageProcessor {
} }
} }
pub fn set_cross_program_support(&mut self, is_supported: bool) { fn get_compute_budget(feature_set: &FeatureSet) -> ComputeBudget {
self.is_cross_program_supported = is_supported; if feature_set.is_active(&compute_budget_config2::id()) {
} ComputeBudget::default()
} else {
pub fn set_compute_budget(&mut self, compute_budget: ComputeBudget) { // Original
self.compute_budget = compute_budget; ComputeBudget {
} max_units: 100_000,
log_units: 0,
#[cfg(test)] log_64_units: 0,
pub fn get_cross_program_support(&mut self) -> bool { create_program_address_units: 0,
self.is_cross_program_supported invoke_units: 0,
max_invoke_depth: 2,
}
}
} }
/// Create the KeyedAccounts that will be passed to the program /// Create the KeyedAccounts that will be passed to the program
@ -527,10 +519,6 @@ impl MessageProcessor {
accounts: &[Rc<RefCell<Account>>], accounts: &[Rc<RefCell<Account>>],
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if !self.is_cross_program_supported {
return Err(InstructionError::ReentrancyNotAllowed);
}
let instruction = &message.instructions[0]; let instruction = &message.instructions[0];
// Verify the calling program hasn't misbehaved // Verify the calling program hasn't misbehaved
@ -681,11 +669,11 @@ impl MessageProcessor {
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
instruction_index: usize, instruction_index: usize,
feature_set: &FeatureSet, feature_set: Arc<FeatureSet>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// Fixup the special instructions key if present // Fixup the special instructions key if present
// before the account pre-values are taken care of // before the account pre-values are taken care of
if feature_set.is_active(&feature_set::instructions_sysvar_enabled::id()) { if feature_set.is_active(&instructions_sysvar_enabled::id()) {
for (i, key) in message.account_keys.iter().enumerate() { for (i, key) in message.account_keys.iter().enumerate() {
if solana_sdk::sysvar::instructions::check_id(key) { if solana_sdk::sysvar::instructions::check_id(key) {
let mut mut_account_ref = accounts[i].borrow_mut(); let mut mut_account_ref = accounts[i].borrow_mut();
@ -705,10 +693,10 @@ impl MessageProcessor {
pre_accounts, pre_accounts,
self.programs.clone(), // get rid of clone self.programs.clone(), // get rid of clone
log_collector, log_collector,
self.is_cross_program_supported, Self::get_compute_budget(&feature_set),
self.compute_budget,
executors, executors,
instruction_recorder, instruction_recorder,
feature_set,
); );
let keyed_accounts = let keyed_accounts =
Self::create_keyed_accounts(message, instruction, executable_accounts, accounts)?; Self::create_keyed_accounts(message, instruction, executable_accounts, accounts)?;
@ -737,7 +725,7 @@ impl MessageProcessor {
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorders: Option<&[InstructionRecorder]>, instruction_recorders: Option<&[InstructionRecorder]>,
feature_set: &FeatureSet, feature_set: Arc<FeatureSet>,
) -> Result<(), TransactionError> { ) -> Result<(), TransactionError> {
for (instruction_index, instruction) in message.instructions.iter().enumerate() { for (instruction_index, instruction) in message.instructions.iter().enumerate() {
let instruction_recorder = instruction_recorders let instruction_recorder = instruction_recorders
@ -753,7 +741,7 @@ impl MessageProcessor {
executors.clone(), executors.clone(),
instruction_recorder, instruction_recorder,
instruction_index, instruction_index,
feature_set, feature_set.clone(),
) )
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?; .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
} }
@ -798,10 +786,10 @@ mod tests {
pre_accounts, pre_accounts,
vec![], vec![],
None, None,
true,
ComputeBudget::default(), ComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,
Arc::new(FeatureSet::default()),
); );
// Check call depth increases and has a limit // Check call depth increases and has a limit
@ -1338,7 +1326,7 @@ mod tests {
None, None,
executors.clone(), executors.clone(),
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 100); assert_eq!(accounts[0].borrow().lamports, 100);
@ -1361,7 +1349,7 @@ mod tests {
None, None,
executors.clone(), executors.clone(),
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1388,7 +1376,7 @@ mod tests {
None, None,
executors, executors,
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1498,7 +1486,7 @@ mod tests {
None, None,
executors.clone(), executors.clone(),
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1525,7 +1513,7 @@ mod tests {
None, None,
executors.clone(), executors.clone(),
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
@ -1549,7 +1537,7 @@ mod tests {
None, None,
executors, executors,
None, None,
&FeatureSet::default(), Arc::new(FeatureSet::default()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 80); assert_eq!(accounts[0].borrow().lamports, 80);
@ -1623,10 +1611,10 @@ mod tests {
vec![owned_preaccount, not_owned_preaccount], vec![owned_preaccount, not_owned_preaccount],
vec![], vec![],
None, None,
true,
ComputeBudget::default(), ComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,
Arc::new(FeatureSet::default()),
); );
let metas = vec![ let metas = vec![
AccountMeta::new(owned_key, false), AccountMeta::new(owned_key, false),

View File

@ -56,10 +56,8 @@ pub trait InvokeContext {
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)]; fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
/// Get this invocation's logger /// Get this invocation's logger
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>; fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
/// Are cross program invocations supported
fn is_cross_program_supported(&self) -> bool;
/// Get this invocation's compute budget /// Get this invocation's compute budget
fn get_compute_budget(&self) -> ComputeBudget; 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>>;
/// Loaders may need to do work in order to execute a program. Cache /// Loaders may need to do work in order to execute a program. Cache
@ -69,6 +67,8 @@ pub trait InvokeContext {
fn get_executor(&mut self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>>; fn get_executor(&mut self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>>;
/// Record invoked instruction /// Record invoked instruction
fn record_instruction(&self, instruction: &Instruction); fn record_instruction(&self, instruction: &Instruction);
/// Get the bank's active feature set
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]