diff --git a/Cargo.lock b/Cargo.lock index e551396b1d..1902c809f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3699,7 +3699,6 @@ dependencies = [ "solana-logger 1.4.4", "solana-net-utils", "solana-remote-wallet", - "solana-runtime", "solana-sdk 1.4.4", "solana-stake-program", "solana-transaction-status", @@ -4586,6 +4585,7 @@ dependencies = [ "hex", "hmac", "itertools 0.9.0", + "lazy_static", "libsecp256k1", "log 0.4.8", "memmap", @@ -4909,7 +4909,6 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger 1.4.4", - "solana-runtime", "solana-sdk 1.4.4", ] diff --git a/bench-exchange/tests/bench_exchange.rs b/bench-exchange/tests/bench_exchange.rs index ea24fffd14..99446d9516 100644 --- a/bench-exchange/tests/bench_exchange.rs +++ b/bench-exchange/tests/bench_exchange.rs @@ -86,7 +86,7 @@ fn test_exchange_bank_client() { solana_logger::setup(); let (genesis_config, identity) = create_genesis_config(100_000_000_000_000); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("exchange_program", id(), process_instruction); + bank.add_builtin("exchange_program", id(), process_instruction); let clients = vec![BankClient::new(bank)]; let mut config = Config::default(); diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 27ce46b3fa..f06880e30b 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -39,7 +39,6 @@ solana-logger = { path = "../logger", version = "1.4.4" } solana-net-utils = { path = "../net-utils", version = "1.4.4" } solana_rbpf = "=0.1.32" solana-remote-wallet = { path = "../remote-wallet", version = "1.4.4" } -solana-runtime = { path = "../runtime", version = "1.4.4" } solana-sdk = { path = "../sdk", version = "1.4.4" } solana-stake-program = { path = "../programs/stake", version = "1.4.4" } solana-transaction-status = { path = "../transaction-status", version = "1.4.4" } diff --git a/cli/src/feature.rs b/cli/src/feature.rs index 0ea6393c8a..c47e731978 100644 --- a/cli/src/feature.rs +++ b/cli/src/feature.rs @@ -9,12 +9,14 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*}; use solana_cli_output::{QuietDisplay, VerboseDisplay}; use solana_client::{client_error::ClientError, rpc_client::RpcClient}; use solana_remote_wallet::remote_wallet::RemoteWalletManager; -use solana_runtime::{ +use solana_sdk::{ + clock::Slot, feature::{self, Feature}, feature_set::FEATURE_NAMES, -}; -use solana_sdk::{ - clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction, + message::Message, + pubkey::Pubkey, + system_instruction, + transaction::Transaction, }; use std::{collections::HashMap, fmt, sync::Arc}; diff --git a/core/src/cache_block_time_service.rs b/core/src/cache_block_time_service.rs index 714b923c20..1bd03d1a77 100644 --- a/core/src/cache_block_time_service.rs +++ b/core/src/cache_block_time_service.rs @@ -1,8 +1,8 @@ use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; use solana_ledger::blockstore::Blockstore; use solana_measure::measure::Measure; -use solana_runtime::{bank::Bank, feature_set}; -use solana_sdk::timing::slot_duration_from_slots_per_year; +use solana_runtime::bank::Bank; +use solana_sdk::{feature_set, timing::slot_duration_from_slots_per_year}; use std::{ collections::HashMap, sync::{ diff --git a/core/src/cluster_info.rs b/core/src/cluster_info.rs index c32ea08e62..6f53568506 100644 --- a/core/src/cluster_info.rs +++ b/core/src/cluster_info.rs @@ -52,10 +52,10 @@ use solana_perf::packet::{ }; use solana_rayon_threadlimit::get_thread_count; use solana_runtime::bank_forks::BankForks; -use solana_runtime::feature_set::{self, FeatureSet}; -use solana_sdk::hash::Hash; use solana_sdk::{ clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH}, + feature_set::{self, FeatureSet}, + hash::Hash, pubkey::Pubkey, signature::{Keypair, Signable, Signature, Signer}, timing::timestamp, diff --git a/ledger/src/builtins.rs b/ledger/src/builtins.rs index d4926d69fe..2a99f865cb 100644 --- a/ledger/src/builtins.rs +++ b/ledger/src/builtins.rs @@ -1,8 +1,5 @@ -use solana_runtime::{ - bank::{Builtin, Builtins, Entrypoint}, - feature_set, -}; -use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey}; +use solana_runtime::bank::{Builtin, Builtins}; +use solana_sdk::{feature_set, genesis_config::ClusterType, pubkey::Pubkey}; /// Builtin programs that are always available fn genesis_builtins(cluster_type: ClusterType) -> Vec { @@ -19,7 +16,7 @@ fn genesis_builtins(cluster_type: ClusterType) -> Vec { builtins .into_iter() - .map(|b| Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2))) + .map(|b| Builtin::new(&b.0, b.1, b.2)) .collect() } @@ -32,7 +29,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> { builtins .into_iter() - .map(|(b, p)| (Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2)), p)) + .map(|(b, p)| (Builtin::new(&b.0, b.1, b.2), p)) .collect() } diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 101fde5249..5f14eed3e8 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2211,6 +2211,7 @@ dependencies = [ "hex", "hmac", "itertools", + "lazy_static", "libsecp256k1", "log", "memmap", diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index 1702bc1f75..6874169f47 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -11,10 +11,8 @@ use solana_rbpf::vm::{EbpfVm, InstructionMeter}; use solana_runtime::{ bank::Bank, bank_client::BankClient, - bpf_test_utils::MockInvokeContext, genesis_utils::{create_genesis_config, GenesisConfigInfo}, loader_utils::load_program, - process_instruction::{ComputeMeter, InvokeContext}, }; use solana_sdk::{ account::Account, @@ -23,6 +21,7 @@ use solana_sdk::{ entrypoint::SUCCESS, instruction::{AccountMeta, Instruction}, message::Message, + process_instruction::{ComputeMeter, InvokeContext, MockInvokeContext}, pubkey::Pubkey, signature::{Keypair, Signer}, }; @@ -161,7 +160,7 @@ fn bench_program_execute_noop(bencher: &mut Bencher) { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); diff --git a/programs/bpf/c/src/sanity/sanity.c b/programs/bpf/c/src/sanity/sanity.c index e77c4ce8ac..f531796ac8 100644 --- a/programs/bpf/c/src/sanity/sanity.c +++ b/programs/bpf/c/src/sanity/sanity.c @@ -18,5 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) { // program, no account keys or input data are expected but real // programs will have specific requirements so they can do their work. sol_log_params(¶ms); + + sol_log_compute_units(); return SUCCESS; } diff --git a/programs/bpf/rust/sanity/src/lib.rs b/programs/bpf/rust/sanity/src/lib.rs index 059a76d2e3..c4345d6306 100644 --- a/programs/bpf/rust/sanity/src/lib.rs +++ b/programs/bpf/rust/sanity/src/lib.rs @@ -61,6 +61,7 @@ fn process_instruction( panic!(); } + sol_log_compute_units(); Ok(()) } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 7d3ca5b0f8..6717fe1028 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -11,10 +11,8 @@ use solana_rbpf::vm::EbpfVm; use solana_runtime::{ bank::Bank, bank_client::BankClient, - bpf_test_utils::MockInvokeContext, genesis_utils::{create_genesis_config, GenesisConfigInfo}, loader_utils::load_program, - process_instruction::ComputeBudget, }; use solana_sdk::{ account::Account, @@ -25,6 +23,7 @@ use solana_sdk::{ instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, keyed_account::KeyedAccount, message::Message, + process_instruction::{BpfComputeBudget, MockInvokeContext}, pubkey::Pubkey, signature::{Keypair, Signer}, sysvar::{clock, fees, rent, slot_hashes, stake_history}, @@ -179,7 +178,7 @@ fn test_program_bpf_sanity() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank = Arc::new(bank); // Create bank with a specific slot, used by solana_bpf_rust_sysvar test @@ -233,7 +232,7 @@ fn test_program_bpf_loader_deprecated() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank_client = BankClient::new(bank); let program_id = load_bpf_program( @@ -273,7 +272,7 @@ fn test_program_bpf_duplicate_accounts() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program); @@ -358,7 +357,7 @@ fn test_program_bpf_error_handling() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank_client = BankClient::new(bank); let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program); let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)]; @@ -475,7 +474,7 @@ fn test_program_bpf_invoke() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); @@ -706,7 +705,7 @@ fn test_program_bpf_call_depth() { } = create_genesis_config(50); let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank_client = BankClient::new(bank); let program_id = load_bpf_program( &bank_client, @@ -717,14 +716,14 @@ fn test_program_bpf_call_depth() { let instruction = Instruction::new( program_id, - &(ComputeBudget::default().max_call_depth - 1), + &(BpfComputeBudget::default().max_call_depth - 1), vec![], ); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction); assert!(result.is_ok()); let instruction = - Instruction::new(program_id, &ComputeBudget::default().max_call_depth, vec![]); + Instruction::new(program_id, &BpfComputeBudget::default().max_call_depth, vec![]); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction); assert!(result.is_err()); } @@ -788,7 +787,7 @@ fn test_program_bpf_instruction_introspection() { let mut bank = Bank::new(&genesis_config); let (name, id, entrypoint) = solana_bpf_loader_program!(); - bank.add_builtin_loader(&name, id, entrypoint); + bank.add_builtin(&name, id, entrypoint); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index d908c61633..b4bbb614ab 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -16,17 +16,15 @@ use solana_rbpf::{ memory_region::MemoryRegion, vm::{Config, EbpfVm, Executable, InstructionMeter}, }; -use solana_runtime::{ - feature_set::compute_budget_balancing, - process_instruction::{ComputeMeter, Executor, InvokeContext}, -}; use solana_sdk::{ bpf_loader, bpf_loader_deprecated, decode_error::DecodeError, entrypoint::SUCCESS, + feature_set::bpf_compute_budget_balancing, instruction::InstructionError, keyed_account::{is_executable, next_keyed_account, KeyedAccount}, loader_instruction::LoaderInstruction, + process_instruction::{ComputeMeter, Executor, InvokeContext}, program_utils::limited_deserialize, pubkey::Pubkey, }; @@ -101,7 +99,7 @@ pub fn create_and_cache_executor( .map_err(|e| map_ebpf_error(invoke_context, e))?; bpf_verifier::check( elf_bytes, - !invoke_context.is_feature_active(&compute_budget_balancing::id()), + !invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()), ) .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; let executor = Arc::new(BPFExecutor { executable }); @@ -116,12 +114,12 @@ pub fn create_vm<'a>( parameter_accounts: &'a [KeyedAccount<'a>], invoke_context: &'a mut dyn InvokeContext, ) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError> { - let compute_budget = invoke_context.get_compute_budget(); + let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); let mut vm = EbpfVm::new( executable, Config { - max_call_depth: compute_budget.max_call_depth, - stack_frame_size: compute_budget.stack_frame_size, + max_call_depth: bpf_compute_budget.max_call_depth, + stack_frame_size: bpf_compute_budget.stack_frame_size, }, )?; let heap_region = @@ -312,13 +310,14 @@ impl Executor for BPFExecutor { mod tests { use super::*; use rand::Rng; - use solana_runtime::{ - bpf_test_utils::MockInvokeContext, + use solana_runtime::message_processor::{Executors, ThisInvokeContext}; + use solana_sdk::{ + account::Account, feature_set::FeatureSet, - message_processor::{Executors, ThisInvokeContext}, - process_instruction::ComputeBudget, + instruction::InstructionError, + process_instruction::{BpfComputeBudget, MockInvokeContext}, + rent::Rent, }; - use solana_sdk::{account::Account, rent::Rent}; use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc}; struct TestInstructionMeter { @@ -533,9 +532,9 @@ mod tests { &program_id, Rent::default(), vec![], - vec![], + &[], None, - ComputeBudget { + BpfComputeBudget { max_units: 1, log_units: 100, log_64_units: 100, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index b581409838..50b39f3b60 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -7,22 +7,21 @@ use solana_rbpf::{ memory_region::{translate_addr, MemoryRegion}, vm::{EbpfVm, SyscallObject}, }; -use solana_runtime::{ - feature_set::{ - pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled, - }, - message_processor::MessageProcessor, - process_instruction::{ComputeMeter, InvokeContext, Logger}, -}; +use solana_runtime::message_processor::MessageProcessor; use solana_sdk::{ account::Account, account_info::AccountInfo, - bpf_loader, bpf_loader_deprecated, + bpf_loader_deprecated, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, + feature_set::{ + pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled, + sol_log_compute_units_syscall, + }, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, keyed_account::KeyedAccount, message::Message, + process_instruction::{ComputeMeter, InvokeContext, Logger}, program_error::ProgramError, pubkey::{Pubkey, PubkeyError}, }; @@ -98,7 +97,7 @@ pub fn register_syscalls<'a>( callers_keyed_accounts: &'a [KeyedAccount<'a>], invoke_context: &'a mut dyn InvokeContext, ) -> Result> { - let compute_budget = invoke_context.get_compute_budget(); + let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); // Syscall functions common across languages @@ -107,7 +106,7 @@ pub fn register_syscalls<'a>( vm.register_syscall_with_context_ex( "sol_log_", Box::new(SyscallLog { - cost: compute_budget.log_units, + cost: bpf_compute_budget.log_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), loader_id, @@ -116,17 +115,27 @@ pub fn register_syscalls<'a>( vm.register_syscall_with_context_ex( "sol_log_64_", Box::new(SyscallLogU64 { - cost: compute_budget.log_64_units, + cost: bpf_compute_budget.log_64_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), }), )?; + if invoke_context.is_feature_active(&sol_log_compute_units_syscall::id()) { + vm.register_syscall_with_context_ex( + "sol_log_compute_units_", + Box::new(SyscallLogBpfComputeUnits { + cost: 0, + compute_meter: invoke_context.get_compute_meter(), + logger: invoke_context.get_logger(), + }), + )?; + } if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) { vm.register_syscall_with_context_ex( "sol_log_pubkey", Box::new(SyscallLogPubkey { - cost: compute_budget.log_pubkey_units, + cost: bpf_compute_budget.log_pubkey_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), loader_id, @@ -138,8 +147,8 @@ pub fn register_syscalls<'a>( vm.register_syscall_with_context_ex( "sol_sha256", Box::new(SyscallSha256 { - sha256_base_cost: compute_budget.sha256_base_cost, - sha256_byte_cost: compute_budget.sha256_byte_cost, + sha256_base_cost: bpf_compute_budget.sha256_base_cost, + sha256_byte_cost: bpf_compute_budget.sha256_byte_cost, compute_meter: invoke_context.get_compute_meter(), loader_id, }), @@ -160,7 +169,7 @@ pub fn register_syscalls<'a>( vm.register_syscall_with_context_ex( "sol_create_program_address", Box::new(SyscallCreateProgramAddress { - cost: compute_budget.create_program_address_units, + cost: bpf_compute_budget.create_program_address_units, compute_meter: invoke_context.get_compute_meter(), loader_id, }), @@ -414,6 +423,38 @@ impl SyscallObject for SyscallLogU64 { } } +/// Log current compute consumption +pub struct SyscallLogBpfComputeUnits { + cost: u64, + compute_meter: Rc>, + logger: Rc>, +} +impl SyscallObject for SyscallLogBpfComputeUnits { + fn call( + &mut self, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + _ro_regions: &[MemoryRegion], + _rw_regions: &[MemoryRegion], + ) -> Result> { + self.compute_meter.consume(self.cost)?; + let mut logger = self + .logger + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; + if logger.log_enabled() { + logger.log(&format!( + "Program consumption: {} units remaining", + self.compute_meter.borrow().get_remaining() + )); + } + Ok(0) + } +} + /// Log 5 64-bit values pub struct SyscallLogPubkey<'a> { cost: u64, @@ -1147,7 +1188,7 @@ fn call<'a>( let mut invoke_context = syscall.get_context_mut()?; invoke_context .get_compute_meter() - .consume(invoke_context.get_compute_budget().invoke_units)?; + .consume(invoke_context.get_bpf_compute_budget().invoke_units)?; // Translate data passed from the VM @@ -1185,8 +1226,6 @@ fn call<'a>( for (program_id, process_instruction) in invoke_context.get_programs().iter() { message_processor.add_program(*program_id, *process_instruction); } - message_processor.add_loader(bpf_loader::id(), crate::process_instruction); - message_processor.add_loader(bpf_loader_deprecated::id(), crate::process_instruction); #[allow(clippy::deref_addrof)] match message_processor.process_cross_program_instruction( @@ -1237,8 +1276,11 @@ fn call<'a>( #[cfg(test)] mod tests { use super::*; - use solana_runtime::bpf_test_utils::{MockComputeMeter, MockLogger}; - use solana_sdk::hash::hashv; + use solana_sdk::{ + bpf_loader, + hash::hashv, + process_instruction::{MockComputeMeter, MockLogger}, + }; use std::str::FromStr; macro_rules! assert_access_violation { diff --git a/programs/budget/src/budget_processor.rs b/programs/budget/src/budget_processor.rs index 3fbe344c0c..f79ff118ce 100644 --- a/programs/budget/src/budget_processor.rs +++ b/programs/budget/src/budget_processor.rs @@ -10,6 +10,7 @@ use solana_sdk::{ hash::hash, instruction::InstructionError, keyed_account::{next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, }; @@ -116,6 +117,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let keyed_accounts_iter = &mut keyed_accounts.iter(); let instruction = limited_deserialize(data)?; @@ -238,7 +240,7 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("budget_program", id(), process_instruction); + bank.add_builtin("budget_program", id(), process_instruction); (bank, mint_keypair) } diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index 177b3cd073..c91e2c93d2 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -3,15 +3,19 @@ use crate::ConfigKeys; use bincode::deserialize; use log::*; -use solana_sdk::instruction::InstructionError; -use solana_sdk::keyed_account::{next_keyed_account, KeyedAccount}; -use solana_sdk::program_utils::limited_deserialize; -use solana_sdk::pubkey::Pubkey; +use solana_sdk::{ + instruction::InstructionError, + keyed_account::{next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, + program_utils::limited_deserialize, + pubkey::Pubkey, +}; pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let key_list: ConfigKeys = limited_deserialize(data)?; let keyed_accounts_iter = &mut keyed_accounts.iter(); @@ -109,6 +113,7 @@ mod tests { use solana_sdk::{ account::Account, keyed_account::create_keyed_is_signer_accounts, + process_instruction::MockInvokeContext, signature::{Keypair, Signer}, system_instruction::SystemInstruction, }; @@ -162,7 +167,12 @@ mod tests { let accounts = vec![(&config_pubkey, true, &config_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instructions[1].data), + process_instruction( + &id(), + &keyed_accounts, + &instructions[1].data, + &mut MockInvokeContext::default() + ), Ok(()) ); @@ -192,7 +202,12 @@ mod tests { let accounts = vec![(&config_pubkey, true, &config_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); assert_eq!( @@ -214,7 +229,12 @@ mod tests { let accounts = vec![(&config_pubkey, true, &config_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::InvalidInstructionData) ); } @@ -232,7 +252,12 @@ mod tests { let accounts = vec![(&config_pubkey, false, &config_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); } @@ -262,7 +287,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); @@ -288,7 +318,12 @@ mod tests { let accounts = vec![(&signer0_pubkey, true, &signer0_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::InvalidAccountData) ); } @@ -314,7 +349,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); @@ -325,7 +365,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); } @@ -357,7 +402,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); @@ -372,7 +422,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); @@ -392,7 +447,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); @@ -410,7 +470,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); } @@ -443,7 +508,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); @@ -457,7 +527,12 @@ mod tests { ]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Ok(()) ); let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); @@ -473,7 +548,12 @@ mod tests { let accounts = vec![(&config_pubkey, true, &config_account)]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instruction.data), + process_instruction( + &id(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default() + ), Err(InstructionError::MissingRequiredSignature) ); } @@ -487,7 +567,12 @@ mod tests { let accounts = vec![]; let keyed_accounts = create_keyed_is_signer_accounts(&accounts); assert_eq!( - process_instruction(&id(), &keyed_accounts, &instructions[1].data), + process_instruction( + &id(), + &keyed_accounts, + &instructions[1].data, + &mut MockInvokeContext::default() + ), Err(InstructionError::NotEnoughAccountKeys) ); } diff --git a/programs/exchange/src/exchange_processor.rs b/programs/exchange/src/exchange_processor.rs index c01aa290f2..2cf146ee72 100644 --- a/programs/exchange/src/exchange_processor.rs +++ b/programs/exchange/src/exchange_processor.rs @@ -9,7 +9,7 @@ use serde_derive::Serialize; use solana_metrics::inc_new_counter_info; use solana_sdk::{ decode_error::DecodeError, instruction::InstructionError, keyed_account::KeyedAccount, - program_utils::limited_deserialize, pubkey::Pubkey, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, }; use std::cmp; use thiserror::Error; @@ -464,6 +464,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { solana_logger::setup(); @@ -578,7 +579,7 @@ mod test { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("exchange_program", id(), process_instruction); + bank.add_builtin("exchange_program", id(), process_instruction); (bank, mint_keypair) } diff --git a/programs/failure/src/lib.rs b/programs/failure/src/lib.rs index 3225355d3a..f55ae06f5d 100644 --- a/programs/failure/src/lib.rs +++ b/programs/failure/src/lib.rs @@ -1,6 +1,7 @@ -use solana_sdk::instruction::InstructionError; -use solana_sdk::keyed_account::KeyedAccount; -use solana_sdk::pubkey::Pubkey; +use solana_sdk::{ + instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext, + pubkey::Pubkey, +}; solana_sdk::declare_program!( "FaiLure111111111111111111111111111111111111", @@ -12,6 +13,7 @@ fn process_instruction( _program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { Err(InstructionError::Custom(0)) } diff --git a/programs/noop/src/lib.rs b/programs/noop/src/lib.rs index fb9548f5cf..2580f4ef53 100644 --- a/programs/noop/src/lib.rs +++ b/programs/noop/src/lib.rs @@ -1,7 +1,8 @@ use log::*; -use solana_sdk::instruction::InstructionError; -use solana_sdk::keyed_account::KeyedAccount; -use solana_sdk::pubkey::Pubkey; +use solana_sdk::{ + instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext, + pubkey::Pubkey, +}; solana_sdk::declare_program!( "Noop111111111111111111111111111111111111111", @@ -13,6 +14,7 @@ fn process_instruction( program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { solana_logger::setup(); trace!("noop: program_id: {:?}", program_id); diff --git a/programs/ownable/src/ownable_processor.rs b/programs/ownable/src/ownable_processor.rs index 785600c981..ecfda56da1 100644 --- a/programs/ownable/src/ownable_processor.rs +++ b/programs/ownable/src/ownable_processor.rs @@ -5,6 +5,7 @@ use bincode::serialize_into; use solana_sdk::{ instruction::InstructionError, keyed_account::{next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, }; @@ -30,6 +31,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let new_owner_pubkey: Pubkey = limited_deserialize(data)?; let keyed_accounts_iter = &mut keyed_accounts.iter(); @@ -71,7 +73,7 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("ownable_program", crate::id(), process_instruction); + bank.add_builtin("ownable_program", crate::id(), process_instruction); (bank, mint_keypair) } diff --git a/programs/secp256k1/src/lib.rs b/programs/secp256k1/src/lib.rs index abba7bf2b0..2981819c25 100644 --- a/programs/secp256k1/src/lib.rs +++ b/programs/secp256k1/src/lib.rs @@ -1,24 +1,20 @@ -use solana_sdk::pubkey::Pubkey; use solana_sdk::{ instruction::{Instruction, InstructionError}, keyed_account::KeyedAccount, + process_instruction::InvokeContext, + pubkey::Pubkey, }; pub fn process_instruction( _program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { // Should be already checked by now. Ok(()) } -solana_sdk::declare_program!( - solana_sdk::secp256k1_program::ID, - solana_keccak_secp256k1_program, - process_instruction -); - pub fn new_secp256k1_instruction( priv_key: &secp256k1::SecretKey, message_arr: &[u8], diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 8175cb0692..789b8d114f 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -10,6 +10,7 @@ use solana_sdk::{ decode_error::DecodeError, instruction::{AccountMeta, Instruction, InstructionError}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction, @@ -446,6 +447,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { trace!("process_instruction: {:?}", data); trace!("keyed_accounts: {:?}", keyed_accounts); @@ -525,6 +527,7 @@ mod tests { use bincode::serialize; use solana_sdk::{ account::{self, Account}, + process_instruction::MockInvokeContext, rent::Rent, sysvar::stake_history::StakeHistory, }; @@ -562,7 +565,12 @@ mod tests { .zip(accounts.iter()) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .collect(); - super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data) + super::process_instruction( + &Pubkey::default(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default(), + ) } } @@ -661,6 +669,7 @@ mod tests { Lockup::default() )) .unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); @@ -679,6 +688,7 @@ mod tests { Lockup::default() )) .unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); @@ -696,6 +706,7 @@ mod tests { Lockup::default() )) .unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::InvalidArgument), ); @@ -717,6 +728,7 @@ mod tests { Lockup::default() )) .unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::InvalidAccountData), ); @@ -731,6 +743,7 @@ mod tests { &create_default_account() ),], &serialize(&StakeInstruction::DelegateStake).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); @@ -745,6 +758,7 @@ mod tests { &create_default_account() )], &serialize(&StakeInstruction::DelegateStake).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); @@ -776,6 +790,7 @@ mod tests { ), ], &serialize(&StakeInstruction::DelegateStake).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::InvalidAccountData), ); @@ -802,6 +817,7 @@ mod tests { ), ], &serialize(&StakeInstruction::Withdraw(42)).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::InvalidArgument), ); @@ -816,6 +832,7 @@ mod tests { &create_default_account() )], &serialize(&StakeInstruction::Withdraw(42)).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); @@ -836,6 +853,7 @@ mod tests { ), ], &serialize(&StakeInstruction::Deactivate).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::InvalidArgument), ); @@ -846,6 +864,7 @@ mod tests { &Pubkey::default(), &[], &serialize(&StakeInstruction::Deactivate).unwrap(), + &mut MockInvokeContext::default() ), Err(InstructionError::NotEnoughAccountKeys), ); diff --git a/programs/vest/src/vest_processor.rs b/programs/vest/src/vest_processor.rs index 20a0f8f2b1..bd40f31ae5 100644 --- a/programs/vest/src/vest_processor.rs +++ b/programs/vest/src/vest_processor.rs @@ -10,6 +10,7 @@ use solana_sdk::{ account::Account, instruction::InstructionError, keyed_account::{next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, }; @@ -59,6 +60,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let keyed_accounts_iter = &mut keyed_accounts.iter(); let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?; @@ -162,7 +164,7 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("vest_program", id(), process_instruction); + bank.add_builtin("vest_program", id(), process_instruction); (bank, mint_keypair) } diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index 52ff66ae43..5cbff6bdf5 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -14,6 +14,7 @@ use solana_sdk::{ hash::Hash, instruction::{AccountMeta, Instruction, InstructionError}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction, @@ -277,6 +278,7 @@ pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { trace!("process_instruction: {:?}", data); trace!("keyed_accounts: {:?}", keyed_accounts); @@ -333,6 +335,7 @@ mod tests { use super::*; use solana_sdk::{ account::{self, Account}, + process_instruction::MockInvokeContext, rent::Rent, }; use std::cell::RefCell; @@ -341,7 +344,12 @@ mod tests { #[test] fn test_vote_process_instruction_decode_bail() { assert_eq!( - super::process_instruction(&Pubkey::default(), &[], &[],), + super::process_instruction( + &Pubkey::default(), + &[], + &[], + &mut MockInvokeContext::default() + ), Err(InstructionError::NotEnoughAccountKeys), ); } @@ -374,7 +382,12 @@ mod tests { .zip(accounts.iter()) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .collect(); - super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data) + super::process_instruction( + &Pubkey::default(), + &keyed_accounts, + &instruction.data, + &mut MockInvokeContext::default(), + ) } } diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index 3283a36be0..3e84cbbbdf 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -12,6 +12,7 @@ use solana_sdk::{ instruction::InstructionError, keyed_account::KeyedAccount, message::Message, + process_instruction::InvokeContext, pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, @@ -33,6 +34,7 @@ fn process_instruction( _program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { Ok(()) } @@ -123,7 +125,7 @@ fn do_bench_transactions( let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000); genesis_config.ticks_per_slot = 100; let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program( + bank.add_builtin( "builtin_program", Pubkey::new(&BUILTIN_PROGRAM_ID), process_instruction, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 0fbedc8575..19f5146026 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -17,10 +17,6 @@ use crate::{ instruction_recorder::InstructionRecorder, log_collector::LogCollector, message_processor::{Executors, MessageProcessor}, - process_instruction::{ - ErasedProcessInstruction, ErasedProcessInstructionWithContext, Executor, - ProcessInstruction, ProcessInstructionWithContext, - }, rent_collector::RentCollector, stakes::Stakes, status_cache::{SlotDelta, StatusCache}, @@ -55,6 +51,7 @@ use solana_sdk::{ native_loader, native_token::sol_to_lamports, nonce, nonce_account, + process_instruction::{BpfComputeBudget, Executor, ProcessInstructionWithContext}, program_utils::limited_deserialize, pubkey::Pubkey, recent_blockhashes_account, @@ -138,52 +135,33 @@ type RentCollectionCycleParams = ( type EpochCount = u64; -#[derive(Copy, Clone)] -pub enum Entrypoint { - Program(ProcessInstruction), - Loader(ProcessInstructionWithContext), -} - -impl fmt::Debug for Entrypoint { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[derive(Debug)] - enum EntrypointForDebug { - Program(String), - Loader(String), - } - // rustc doesn't compile due to bug without this work around - // https://github.com/rust-lang/rust/issues/50280 - // https://users.rust-lang.org/t/display-function-pointer/17073/2 - let entrypoint = match self { - Entrypoint::Program(instruction) => EntrypointForDebug::Program(format!( - "{:p}", - *instruction as ErasedProcessInstruction - )), - Entrypoint::Loader(instruction) => EntrypointForDebug::Loader(format!( - "{:p}", - *instruction as ErasedProcessInstructionWithContext - )), - }; - write!(f, "{:?}", entrypoint) - } -} - -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Builtin { pub name: String, pub id: Pubkey, - pub entrypoint: Entrypoint, + pub process_instruction_with_context: ProcessInstructionWithContext, } + impl Builtin { - pub fn new(name: &str, id: Pubkey, entrypoint: Entrypoint) -> Self { + pub fn new( + name: &str, + id: Pubkey, + process_instruction_with_context: ProcessInstructionWithContext, + ) -> Self { Self { name: name.to_string(), id, - entrypoint, + process_instruction_with_context, } } } +impl fmt::Debug for Builtin { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Builtin [name={}, id={}]", self.name, self.id) + } +} + /// Copy-on-write holder of CachedExecutors #[derive(AbiExample, Debug, Default)] struct CowCachedExecutors { @@ -224,7 +202,7 @@ impl AbiExample for Builtin { Self { name: String::default(), id: Pubkey::default(), - entrypoint: Entrypoint::Program(|_, _, _| Ok(())), + process_instruction_with_context: |_, _, _, _| Ok(()), } } } @@ -693,6 +671,8 @@ pub struct Bank { /// The Message processor message_processor: MessageProcessor, + bpf_compute_budget: Option, + /// Builtin programs activated dynamically by feature feature_builtins: Arc>, @@ -829,6 +809,7 @@ impl Bank { tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)), signature_count: AtomicU64::new(0), message_processor: parent.message_processor.clone(), + bpf_compute_budget: parent.bpf_compute_budget, feature_builtins: parent.feature_builtins.clone(), hard_forks: parent.hard_forks.clone(), last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)), @@ -934,6 +915,7 @@ impl Bank { epoch_stakes: fields.epoch_stakes, is_delta: AtomicBool::new(fields.is_delta), message_processor: new(), + bpf_compute_budget: None, feature_builtins: new(), last_vote_sync: new(), rewards: new(), @@ -2375,6 +2357,9 @@ impl Bank { let mut inner_instructions: Vec> = Vec::with_capacity(txs.len()); let mut transaction_logs: Vec = Vec::with_capacity(txs.len()); + let bpf_compute_budget = self + .bpf_compute_budget + .unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set)); let executed: Vec = loaded_accounts .iter_mut() @@ -2413,6 +2398,7 @@ impl Bank { executors.clone(), instruction_recorders.as_deref(), self.feature_set.clone(), + bpf_compute_budget, ); if enable_log_recording { @@ -3365,7 +3351,11 @@ impl Bank { .extend_from_slice(&additional_builtins.feature_builtins); } for builtin in builtins.genesis_builtins { - self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint); + self.add_builtin( + &builtin.name, + builtin.id, + builtin.process_instruction_with_context, + ); } self.feature_builtins = Arc::new(builtins.feature_builtins); @@ -3376,6 +3366,10 @@ impl Bank { *self.inflation.write().unwrap() = inflation; } + pub fn set_bpf_compute_budget(&mut self, bpf_compute_budget: Option) { + self.bpf_compute_budget = bpf_compute_budget; + } + pub fn hard_forks(&self) -> Arc> { self.hard_forks.clone() } @@ -3823,43 +3817,17 @@ impl Bank { !self.is_delta.load(Relaxed) } - pub fn add_builtin_program( - &mut self, - name: &str, - program_id: Pubkey, - process_instruction: ProcessInstruction, - ) { - self.add_builtin(name, program_id, Entrypoint::Program(process_instruction)); - } - - pub fn add_builtin_loader( + /// Add an instruction processor to intercept instructions before the dynamic loader. + pub fn add_builtin( &mut self, name: &str, program_id: Pubkey, process_instruction_with_context: ProcessInstructionWithContext, ) { - self.add_builtin( - name, - program_id, - Entrypoint::Loader(process_instruction_with_context), - ); - } - - /// Add an instruction processor to intercept instructions before the dynamic loader. - pub fn add_builtin(&mut self, name: &str, program_id: Pubkey, entrypoint: Entrypoint) { + debug!("Added program {} under {:?}", name, program_id); self.add_native_program(name, &program_id); - match entrypoint { - Entrypoint::Program(process_instruction) => { - self.message_processor - .add_program(program_id, process_instruction); - debug!("Added builtin program {} under {:?}", name, program_id); - } - Entrypoint::Loader(process_instruction_with_context) => { - self.message_processor - .add_loader(program_id, process_instruction_with_context); - debug!("Added builtin loader {} under {:?}", name, program_id); - } - } + self.message_processor + .add_program(program_id, process_instruction_with_context); } pub fn clean_accounts(&self, skip_last: bool) { @@ -3995,7 +3963,11 @@ impl Bank { let should_populate = init_or_warp && self.feature_set.is_active(&feature) || !init_or_warp && new_feature_activations.contains(&feature); if should_populate { - self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint); + self.add_builtin( + &builtin.name, + builtin.id, + builtin.process_instruction_with_context, + ); } } } @@ -4125,7 +4097,6 @@ mod tests { BOOTSTRAP_VALIDATOR_LAMPORTS, }, native_loader::NativeLoaderError, - process_instruction::InvokeContext, status_cache::MAX_CACHE_ENTRIES, }; use solana_sdk::{ @@ -4138,6 +4109,7 @@ mod tests { message::{Message, MessageHeader}, nonce, poh_config::PohConfig, + process_instruction::InvokeContext, rent::Rent, signature::{Keypair, Signer}, system_instruction::{self, SystemError}, @@ -4428,6 +4400,7 @@ mod tests { _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> result::Result<(), InstructionError> { if let Ok(instruction) = bincode::deserialize(data) { match instruction { @@ -4577,7 +4550,7 @@ mod tests { ) as u64, ); bank.rent_collector.slots_per_year = 421_812.0; - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin("mock_program", mock_program_id, mock_process_instruction); bank } @@ -7713,7 +7686,7 @@ mod tests { } #[test] - fn test_add_builtin_program() { + fn test_add_builtin() { let (genesis_config, mint_keypair) = create_genesis_config(500); let mut bank = Bank::new(&genesis_config); @@ -7724,6 +7697,7 @@ mod tests { program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _instruction_data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> std::result::Result<(), InstructionError> { if mock_vote_program_id() != *program_id { return Err(InstructionError::IncorrectProgramId); @@ -7732,7 +7706,7 @@ mod tests { } assert!(bank.get_account(&mock_vote_program_id()).is_none()); - bank.add_builtin_program( + bank.add_builtin( "mock_vote_program", mock_vote_program_id(), mock_vote_processor, @@ -7781,6 +7755,7 @@ mod tests { _pubkey: &Pubkey, _ka: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> std::result::Result<(), InstructionError> { Err(InstructionError::Custom(42)) } @@ -7805,7 +7780,7 @@ mod tests { ); let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap(); - bank.add_builtin_program( + bank.add_builtin( "solana_vote_program", solana_vote_program::id(), mock_vote_processor, @@ -7831,6 +7806,7 @@ mod tests { _pubkey: &Pubkey, _ka: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> std::result::Result<(), InstructionError> { Err(InstructionError::Custom(42)) } @@ -7850,15 +7826,15 @@ mod tests { assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty()); assert_eq!(bank.calculate_capitalization(), bank.capitalization()); - bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor); - bank.add_builtin_program("mock_program2", stake_id, mock_ix_processor); + bank.add_builtin("mock_program1", vote_id, mock_ix_processor); + bank.add_builtin("mock_program2", stake_id, mock_ix_processor); assert!(bank.stakes.read().unwrap().vote_accounts().is_empty()); assert!(bank.stakes.read().unwrap().stake_delegations().is_empty()); assert_eq!(bank.calculate_capitalization(), bank.capitalization()); // Re-adding builtin programs should be no-op - bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor); - bank.add_builtin_program("mock_program2", stake_id, mock_ix_processor); + bank.add_builtin("mock_program1", vote_id, mock_ix_processor); + bank.add_builtin("mock_program2", stake_id, mock_ix_processor); assert!(bank.stakes.read().unwrap().vote_accounts().is_empty()); assert!(bank.stakes.read().unwrap().stake_delegations().is_empty()); assert_eq!(bank.calculate_capitalization(), bank.capitalization()); @@ -8499,6 +8475,7 @@ mod tests { _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> result::Result<(), InstructionError> { let lamports = data[0] as u64; { @@ -8513,7 +8490,7 @@ mod tests { } let mock_program_id = Pubkey::new(&[2u8; 32]); - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin("mock_program", mock_program_id, mock_process_instruction); let from_pubkey = solana_sdk::pubkey::new_rand(); let to_pubkey = solana_sdk::pubkey::new_rand(); @@ -8551,12 +8528,13 @@ mod tests { _program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> result::Result<(), InstructionError> { Ok(()) } let mock_program_id = Pubkey::new(&[2u8; 32]); - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin("mock_program", mock_program_id, mock_process_instruction); let from_pubkey = solana_sdk::pubkey::new_rand(); let to_pubkey = solana_sdk::pubkey::new_rand(); @@ -8608,7 +8586,7 @@ mod tests { tx.message.account_keys.push(solana_sdk::pubkey::new_rand()); - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), mock_ok_vote_processor, @@ -8662,7 +8640,7 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), mock_ok_vote_processor, @@ -8695,7 +8673,7 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), mock_ok_vote_processor, @@ -8733,6 +8711,7 @@ mod tests { _pubkey: &Pubkey, _ka: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> std::result::Result<(), InstructionError> { Ok(()) } @@ -8750,7 +8729,7 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), mock_ok_vote_processor, @@ -8786,7 +8765,7 @@ mod tests { .map(|i| { let key = solana_sdk::pubkey::new_rand(); let name = format!("program{:?}", i); - bank.add_builtin_program(&name, key, mock_ok_vote_processor); + bank.add_builtin(&name, key, mock_ok_vote_processor); (key, name.as_bytes().to_vec()) }) .collect(); @@ -8981,6 +8960,7 @@ mod tests { _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> result::Result<(), InstructionError> { assert_eq!(42, keyed_accounts[0].lamports().unwrap()); let mut account = keyed_accounts[0].try_account_ref_mut()?; @@ -8993,7 +8973,7 @@ mod tests { // Add a new program let program1_pubkey = solana_sdk::pubkey::new_rand(); - bank.add_builtin_program("program", program1_pubkey, nested_processor); + bank.add_builtin("program", program1_pubkey, nested_processor); // Add a new program owned by the first let program2_pubkey = solana_sdk::pubkey::new_rand(); @@ -9155,13 +9135,14 @@ mod tests { } #[test] - fn test_add_builtin_program_no_overwrite() { + fn test_add_builtin_no_overwrite() { let (genesis_config, _mint_keypair) = create_genesis_config(100_000); fn mock_ix_processor( _pubkey: &Pubkey, _ka: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> std::result::Result<(), InstructionError> { Ok(()) } @@ -9176,19 +9157,15 @@ mod tests { )); assert_eq!(bank.get_account_modified_slot(&program_id), None); - Arc::get_mut(&mut bank).unwrap().add_builtin_program( - "mock_program", - program_id, - mock_ix_processor, - ); + Arc::get_mut(&mut bank) + .unwrap() + .add_builtin("mock_program", program_id, mock_ix_processor); assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); let mut bank = Arc::new(new_from_parent(&bank)); - Arc::get_mut(&mut bank).unwrap().add_builtin_program( - "mock_program", - program_id, - mock_ix_processor, - ); + Arc::get_mut(&mut bank) + .unwrap() + .add_builtin("mock_program", program_id, mock_ix_processor); assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); } @@ -9215,19 +9192,15 @@ mod tests { )); assert_eq!(bank.get_account_modified_slot(&loader_id), None); - Arc::get_mut(&mut bank).unwrap().add_builtin_loader( - "mock_program", - loader_id, - mock_ix_processor, - ); + Arc::get_mut(&mut bank) + .unwrap() + .add_builtin("mock_program", loader_id, mock_ix_processor); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); let mut bank = Arc::new(new_from_parent(&bank)); - Arc::get_mut(&mut bank).unwrap().add_builtin_loader( - "mock_program", - loader_id, - mock_ix_processor, - ); + Arc::get_mut(&mut bank) + .unwrap() + .add_builtin("mock_program", loader_id, mock_ix_processor); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); } @@ -10061,25 +10034,4 @@ mod tests { let debug = format!("{:#?}", bank); assert!(!debug.is_empty()); } - - #[test] - fn test_debug_entrypoint() { - fn mock_process_instruction( - _program_id: &Pubkey, - _keyed_accounts: &[KeyedAccount], - _data: &[u8], - ) -> std::result::Result<(), InstructionError> { - Ok(()) - } - fn mock_ix_processor( - _pubkey: &Pubkey, - _ka: &[KeyedAccount], - _data: &[u8], - _context: &mut dyn InvokeContext, - ) -> std::result::Result<(), InstructionError> { - Ok(()) - } - assert!(!format!("{:?}", Entrypoint::Program(mock_process_instruction)).is_empty()); - assert!(!format!("{:?}", Entrypoint::Loader(mock_ix_processor)).is_empty()); - } } diff --git a/runtime/src/bpf_test_utils.rs b/runtime/src/bpf_test_utils.rs deleted file mode 100644 index 8a7b43a77a..0000000000 --- a/runtime/src/bpf_test_utils.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::process_instruction::{ - ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction, -}; -use solana_sdk::{ - account::Account, instruction::CompiledInstruction, instruction::Instruction, - instruction::InstructionError, message::Message, pubkey::Pubkey, -}; -use std::{cell::RefCell, rc::Rc, sync::Arc}; - -#[derive(Debug, Default, Clone)] -pub struct MockComputeMeter { - pub remaining: u64, -} -impl ComputeMeter for MockComputeMeter { - fn consume(&mut self, amount: u64) -> Result<(), InstructionError> { - let exceeded = self.remaining < amount; - self.remaining = self.remaining.saturating_sub(amount); - if exceeded { - return Err(InstructionError::ComputationalBudgetExceeded); - } - Ok(()) - } - fn get_remaining(&self) -> u64 { - self.remaining - } -} - -#[derive(Debug, Default, Clone)] -pub struct MockLogger { - pub log: Rc>>, -} -impl Logger for MockLogger { - fn log_enabled(&self) -> bool { - true - } - fn log(&mut self, message: &str) { - self.log.borrow_mut().push(message.to_string()); - } -} - -#[derive(Debug)] -pub struct MockInvokeContext { - pub key: Pubkey, - pub logger: MockLogger, - pub compute_budget: ComputeBudget, - pub compute_meter: MockComputeMeter, -} -impl Default for MockInvokeContext { - fn default() -> Self { - MockInvokeContext { - key: Pubkey::default(), - logger: MockLogger::default(), - compute_budget: ComputeBudget::default(), - compute_meter: MockComputeMeter { - remaining: std::i64::MAX as u64, - }, - } - } -} -impl InvokeContext for MockInvokeContext { - fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> { - Ok(()) - } - fn pop(&mut self) {} - fn verify_and_update( - &mut self, - _message: &Message, - _instruction: &CompiledInstruction, - _accounts: &[Rc>], - ) -> Result<(), InstructionError> { - Ok(()) - } - fn get_caller(&self) -> Result<&Pubkey, InstructionError> { - Ok(&self.key) - } - fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] { - &[] - } - fn get_logger(&self) -> Rc> { - Rc::new(RefCell::new(self.logger.clone())) - } - fn get_compute_budget(&self) -> &ComputeBudget { - &self.compute_budget - } - fn get_compute_meter(&self) -> Rc> { - Rc::new(RefCell::new(self.compute_meter.clone())) - } - fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc) {} - fn get_executor(&mut self, _pubkey: &Pubkey) -> Option> { - None - } - fn record_instruction(&self, _instruction: &Instruction) {} - fn is_feature_active(&self, _feature_id: &Pubkey) -> bool { - true - } -} diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index beb8294480..845438fc1a 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -1,5 +1,5 @@ use crate::{ - bank::{Builtin, Builtins, Entrypoint}, + bank::{Builtin, Builtins}, feature_set, system_instruction_processor, }; use solana_sdk::{pubkey::Pubkey, system_program}; @@ -10,22 +10,22 @@ fn genesis_builtins() -> Vec { Builtin::new( "system_program", system_program::id(), - Entrypoint::Program(system_instruction_processor::process_instruction), + system_instruction_processor::process_instruction, ), Builtin::new( "vote_program", solana_vote_program::id(), - Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction), + solana_vote_program::vote_instruction::process_instruction, ), Builtin::new( "stake_program", solana_stake_program::id(), - Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction), + solana_stake_program::stake_instruction::process_instruction, ), Builtin::new( "config_program", solana_config_program::id(), - Entrypoint::Program(solana_config_program::config_processor::process_instruction), + solana_config_program::config_processor::process_instruction, ), ] } @@ -36,7 +36,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> { Builtin::new( "secp256k1_program", solana_sdk::secp256k1_program::id(), - Entrypoint::Program(solana_secp256k1_program::process_instruction), + solana_secp256k1_program::process_instruction, ), feature_set::secp256k1_program_enabled::id(), )] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 078f5605c7..0b994e3549 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -10,12 +10,9 @@ pub mod bank_forks; pub mod bank_utils; mod blockhash_queue; pub mod bloom; -pub mod bpf_test_utils; pub mod builtins; pub mod commitment; pub mod epoch_stakes; -pub mod feature; -pub mod feature_set; pub mod genesis_utils; pub mod hardened_unpack; pub mod instruction_recorder; @@ -23,7 +20,6 @@ pub mod loader_utils; pub mod log_collector; pub mod message_processor; mod native_loader; -pub mod process_instruction; pub mod rent_collector; pub mod serde_snapshot; pub mod snapshot_package; @@ -35,6 +31,10 @@ pub mod transaction_batch; pub mod transaction_utils; pub mod vote_sender_types; +// TODO: Refactor all feature users to reference the solana_sdk definitions directly and remove the +// next line +use solana_sdk::{feature, feature_set}; + extern crate solana_config_program; extern crate solana_stake_program; extern crate solana_vote_program; diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 7d25b869ec..b9570d8ea7 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -3,10 +3,6 @@ use crate::{ instruction_recorder::InstructionRecorder, log_collector::LogCollector, native_loader::NativeLoader, - process_instruction::{ - ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext, - Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext, - }, rent_collector::RentCollector, }; use log::*; @@ -18,6 +14,10 @@ use solana_sdk::{ keyed_account::{create_keyed_readonly_accounts, KeyedAccount}, message::Message, native_loader, + process_instruction::{ + BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, + ProcessInstructionWithContext, + }, pubkey::Pubkey, rent::Rent, system_program, @@ -201,31 +201,31 @@ impl ComputeMeter for ThisComputeMeter { self.remaining } } -pub struct ThisInvokeContext { +pub struct ThisInvokeContext<'a> { program_ids: Vec, rent: Rent, pre_accounts: Vec, - programs: Vec<(Pubkey, ProcessInstruction)>, + programs: &'a [(Pubkey, ProcessInstructionWithContext)], logger: Rc>, - compute_budget: ComputeBudget, + bpf_compute_budget: BpfComputeBudget, compute_meter: Rc>, executors: Rc>, instruction_recorder: Option, feature_set: Arc, } -impl ThisInvokeContext { +impl<'a> ThisInvokeContext<'a> { pub fn new( program_id: &Pubkey, rent: Rent, pre_accounts: Vec, - programs: Vec<(Pubkey, ProcessInstruction)>, + programs: &'a [(Pubkey, ProcessInstructionWithContext)], log_collector: Option>, - compute_budget: ComputeBudget, + bpf_compute_budget: BpfComputeBudget, executors: Rc>, instruction_recorder: Option, feature_set: Arc, ) -> Self { - let mut program_ids = Vec::with_capacity(compute_budget.max_invoke_depth); + let mut program_ids = Vec::with_capacity(bpf_compute_budget.max_invoke_depth); program_ids.push(*program_id); Self { program_ids, @@ -233,9 +233,9 @@ impl ThisInvokeContext { pre_accounts, programs, logger: Rc::new(RefCell::new(ThisLogger { log_collector })), - compute_budget, + bpf_compute_budget, compute_meter: Rc::new(RefCell::new(ThisComputeMeter { - remaining: compute_budget.max_units, + remaining: bpf_compute_budget.max_units, })), executors, instruction_recorder, @@ -243,9 +243,9 @@ impl ThisInvokeContext { } } } -impl InvokeContext for ThisInvokeContext { +impl<'a> InvokeContext for ThisInvokeContext<'a> { fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> { - if self.program_ids.len() > self.compute_budget.max_invoke_depth { + if self.program_ids.len() > self.bpf_compute_budget.max_invoke_depth { return Err(InstructionError::CallDepth); } if self.program_ids.contains(key) && self.program_ids.last() != Some(key) { @@ -281,14 +281,14 @@ impl InvokeContext for ThisInvokeContext { .last() .ok_or(InstructionError::GenericError) } - fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] { - &self.programs + fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] { + self.programs } fn get_logger(&self) -> Rc> { self.logger.clone() } - fn get_compute_budget(&self) -> &ComputeBudget { - &self.compute_budget + fn get_bpf_compute_budget(&self) -> &BpfComputeBudget { + &self.bpf_compute_budget } fn get_compute_meter(&self) -> Rc> { self.compute_meter.clone() @@ -326,9 +326,7 @@ impl Logger for ThisLogger { #[derive(Deserialize, Serialize)] pub struct MessageProcessor { #[serde(skip)] - programs: Vec<(Pubkey, ProcessInstruction)>, - #[serde(skip)] - loaders: Vec<(Pubkey, ProcessInstructionWithContext)>, + programs: Vec<(Pubkey, ProcessInstructionWithContext)>, #[serde(skip)] native_loader: NativeLoader, } @@ -338,9 +336,17 @@ impl std::fmt::Debug for MessageProcessor { #[derive(Debug)] struct MessageProcessor<'a> { programs: Vec, - loaders: Vec, native_loader: &'a NativeLoader, } + + // These are just type aliases for work around of Debug-ing above pointers + type ErasedProcessInstructionWithContext = fn( + &'static Pubkey, + &'static [KeyedAccount<'static>], + &'static [u8], + &'static mut dyn InvokeContext, + ) -> Result<(), InstructionError>; + // rustc doesn't compile due to bug without this work around // https://github.com/rust-lang/rust/issues/50280 // https://users.rust-lang.org/t/display-function-pointer/17073/2 @@ -348,14 +354,6 @@ impl std::fmt::Debug for MessageProcessor { programs: self .programs .iter() - .map(|(pubkey, instruction)| { - let erased_instruction: ErasedProcessInstruction = *instruction; - format!("{}: {:p}", pubkey, erased_instruction) - }) - .collect::>(), - loaders: self - .loaders - .iter() .map(|(pubkey, instruction)| { let erased_instruction: ErasedProcessInstructionWithContext = *instruction; format!("{}: {:p}", pubkey, erased_instruction) @@ -372,7 +370,6 @@ impl Default for MessageProcessor { fn default() -> Self { Self { programs: vec![], - loaders: vec![], native_loader: NativeLoader::default(), } } @@ -381,7 +378,6 @@ impl Clone for MessageProcessor { fn clone(&self) -> Self { MessageProcessor { programs: self.programs.clone(), - loaders: self.loaders.clone(), native_loader: NativeLoader::default(), } } @@ -398,7 +394,11 @@ impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor { impl MessageProcessor { /// Add a static entrypoint to intercept instructions before the dynamic loader. - pub fn add_program(&mut self, program_id: Pubkey, process_instruction: ProcessInstruction) { + pub fn add_program( + &mut self, + program_id: Pubkey, + process_instruction: ProcessInstructionWithContext, + ) { match self.programs.iter_mut().find(|(key, _)| program_id == *key) { Some((_, processor)) => *processor = process_instruction, None => self.programs.push((program_id, process_instruction)), @@ -410,14 +410,7 @@ impl MessageProcessor { program_id: Pubkey, process_instruction: ProcessInstructionWithContext, ) { - match self.loaders.iter_mut().find(|(key, _)| program_id == *key) { - Some((_, processor)) => *processor = process_instruction, - None => self.loaders.push((program_id, process_instruction)), - } - } - - fn get_compute_budget(feature_set: &FeatureSet) -> ComputeBudget { - ComputeBudget::new(feature_set) + self.add_program(program_id, process_instruction); } /// Create the KeyedAccounts that will be passed to the program @@ -458,17 +451,6 @@ impl MessageProcessor { if let Some(root_account) = keyed_accounts.iter().next() { if native_loader::check_id(&root_account.owner()?) { let root_id = root_account.unsigned_key(); - for (id, process_instruction) in &self.loaders { - if id == root_id { - // Call the program via a builtin loader - return process_instruction( - &root_id, - &keyed_accounts[1..], - instruction_data, - invoke_context, - ); - } - } for (id, process_instruction) in &self.programs { if id == root_id { // Call the builtin program @@ -476,6 +458,7 @@ impl MessageProcessor { &root_id, &keyed_accounts[1..], instruction_data, + invoke_context, ); } } @@ -488,7 +471,7 @@ impl MessageProcessor { ); } else { let owner_id = &root_account.owner()?; - for (id, process_instruction) in &self.loaders { + for (id, process_instruction) in &self.programs { if id == owner_id { // Call the program via a builtin loader return process_instruction( @@ -667,6 +650,7 @@ impl MessageProcessor { instruction_recorder: Option, instruction_index: usize, feature_set: Arc, + bpf_compute_budget: BpfComputeBudget, ) -> Result<(), InstructionError> { // Fixup the special instructions key if present // before the account pre-values are taken care of @@ -688,9 +672,9 @@ impl MessageProcessor { instruction.program_id(&message.account_keys), rent_collector.rent, pre_accounts, - self.programs.clone(), // get rid of clone + &self.programs, log_collector, - Self::get_compute_budget(&feature_set), + bpf_compute_budget, executors, instruction_recorder, feature_set, @@ -723,6 +707,7 @@ impl MessageProcessor { executors: Rc>, instruction_recorders: Option<&[InstructionRecorder]>, feature_set: Arc, + bpf_compute_budget: BpfComputeBudget, ) -> Result<(), TransactionError> { for (instruction_index, instruction) in message.instructions.iter().enumerate() { let instruction_recorder = instruction_recorders @@ -739,6 +724,7 @@ impl MessageProcessor { instruction_recorder, instruction_index, feature_set.clone(), + bpf_compute_budget, ) .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?; } @@ -781,9 +767,9 @@ mod tests { &program_ids[0], Rent::default(), pre_accounts, - vec![], + &[], None, - ComputeBudget::default(), + BpfComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), None, Arc::new(FeatureSet::all_enabled()), @@ -1266,6 +1252,7 @@ mod tests { _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if let Ok(instruction) = bincode::deserialize(data) { match instruction { @@ -1327,6 +1314,7 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!(result, Ok(())); assert_eq!(accounts[0].borrow().lamports, 100); @@ -1350,6 +1338,7 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!( result, @@ -1377,6 +1366,7 @@ mod tests { executors, None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!( result, @@ -1400,6 +1390,7 @@ mod tests { _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if let Ok(instruction) = bincode::deserialize(data) { match instruction { @@ -1487,6 +1478,7 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!( result, @@ -1514,6 +1506,7 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!(result, Ok(())); @@ -1538,6 +1531,7 @@ mod tests { executors, None, Arc::new(FeatureSet::all_enabled()), + BpfComputeBudget::new(&FeatureSet::all_enabled()), ); assert_eq!(result, Ok(())); assert_eq!(accounts[0].borrow().lamports, 80); @@ -1559,6 +1553,7 @@ mod tests { program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { assert_eq!(*program_id, keyed_accounts[0].owner()?); assert_ne!( @@ -1609,9 +1604,9 @@ mod tests { &caller_program_id, Rent::default(), vec![owned_preaccount, not_owned_preaccount], - vec![], + &[], None, - ComputeBudget::default(), + BpfComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), None, Arc::new(FeatureSet::all_enabled()), @@ -1675,6 +1670,7 @@ mod tests { _program_id: &Pubkey, _keyed_accounts: &[KeyedAccount], _data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { Ok(()) } diff --git a/runtime/src/native_loader.rs b/runtime/src/native_loader.rs index 9e6c368ee8..20ca59191e 100644 --- a/runtime/src/native_loader.rs +++ b/runtime/src/native_loader.rs @@ -1,5 +1,4 @@ //! Native loader -use crate::process_instruction::{InvokeContext, LoaderEntrypoint}; #[cfg(unix)] use libloading::os::unix::*; #[cfg(windows)] @@ -11,6 +10,7 @@ use solana_sdk::{ entrypoint_native::ProgramEntrypoint, instruction::InstructionError, keyed_account::{next_keyed_account, KeyedAccount}, + process_instruction::{InvokeContext, LoaderEntrypoint}, pubkey::Pubkey, }; use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock}; diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index d8e3d0708d..64b9a7e65c 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -6,6 +6,7 @@ use solana_sdk::{ keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, nonce, nonce_keyed_account::NonceKeyedAccount, + process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH}, @@ -213,6 +214,7 @@ pub fn process_instruction( _owner: &Pubkey, keyed_accounts: &[KeyedAccount], instruction_data: &[u8], + _invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let instruction = limited_deserialize(instruction_data)?; @@ -363,7 +365,9 @@ mod tests { hash::{hash, Hash}, instruction::{AccountMeta, Instruction, InstructionError}, message::Message, - nonce, nonce_account, recent_blockhashes_account, + nonce, nonce_account, + process_instruction::MockInvokeContext, + recent_blockhashes_account, signature::{Keypair, Signer}, system_instruction, system_program, sysvar, sysvar::recent_blockhashes::IterItem, @@ -381,6 +385,19 @@ mod tests { } } + fn process_instruction( + owner: &Pubkey, + keyed_accounts: &[KeyedAccount], + instruction_data: &[u8], + ) -> Result<(), InstructionError> { + super::process_instruction( + owner, + keyed_accounts, + instruction_data, + &mut MockInvokeContext::default(), + ) + } + fn create_default_account() -> RefCell { RefCell::new(Account::default()) } @@ -1194,7 +1211,7 @@ mod tests { .zip(accounts.iter()) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .collect(); - super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data) + process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data) } } @@ -1212,7 +1229,7 @@ mod tests { #[test] fn test_process_nonce_ix_no_keyed_accs_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[], &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap() @@ -1224,7 +1241,7 @@ mod tests { #[test] fn test_process_nonce_ix_only_nonce_acc_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[KeyedAccount::new( &Pubkey::default(), @@ -1240,7 +1257,7 @@ mod tests { #[test] fn test_process_nonce_ix_bad_recent_blockhash_state_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new(&Pubkey::default(), true, &create_default_account()), @@ -1259,7 +1276,7 @@ mod tests { #[test] fn test_process_nonce_ix_ok() { let nonce_acc = nonce_account::create_account(1_000_000); - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new(&Pubkey::default(), true, &nonce_acc), @@ -1288,7 +1305,7 @@ mod tests { ), ); assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,), @@ -1320,7 +1337,7 @@ mod tests { #[test] fn test_process_withdraw_ix_no_keyed_accs_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[], &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), @@ -1332,7 +1349,7 @@ mod tests { #[test] fn test_process_withdraw_ix_only_nonce_acc_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[KeyedAccount::new( &Pubkey::default(), @@ -1348,7 +1365,7 @@ mod tests { #[test] fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new(&Pubkey::default(), true, &create_default_account()), @@ -1368,7 +1385,7 @@ mod tests { #[test] fn test_process_withdraw_ix_bad_rent_state_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new( @@ -1393,7 +1410,7 @@ mod tests { #[test] fn test_process_withdraw_ix_ok() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new( @@ -1418,7 +1435,7 @@ mod tests { #[test] fn test_process_initialize_ix_no_keyed_accs_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[], &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), @@ -1430,7 +1447,7 @@ mod tests { #[test] fn test_process_initialize_ix_only_nonce_acc_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[KeyedAccount::new( &Pubkey::default(), @@ -1446,7 +1463,7 @@ mod tests { #[test] fn test_process_initialize_bad_recent_blockhash_state_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new( @@ -1469,7 +1486,7 @@ mod tests { #[test] fn test_process_initialize_ix_bad_rent_state_fail() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new( @@ -1493,7 +1510,7 @@ mod tests { #[test] fn test_process_initialize_ix_ok() { assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new( @@ -1517,7 +1534,7 @@ mod tests { #[test] fn test_process_authorize_ix_ok() { let nonce_acc = nonce_account::create_account(1_000_000); - super::process_instruction( + process_instruction( &Pubkey::default(), &[ KeyedAccount::new(&Pubkey::default(), true, &nonce_acc), @@ -1532,7 +1549,7 @@ mod tests { ) .unwrap(); assert_eq!( - super::process_instruction( + process_instruction( &Pubkey::default(), &[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),], &serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(), diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 283c2d2022..cbc09c9330 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -46,6 +46,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser hex = "0.4.2" hmac = "0.7.0" itertools = "0.9.0" +lazy_static = "1.4.0" log = "0.4.8" memmap = { version = "0.7.0", optional = true } num-derive = "0.3" diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 0415c2505b..ff7c75f437 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -133,6 +133,12 @@ void sol_log_(const char *, uint64_t); void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); #define sol_log_64 sol_log_64_ +/** + * Prints the current compute unit consumption to stdout + */ +void sol_log_compute_units_(); +#define sol_log_compute_units() sol_log_compute_units_() + /** * Size of Public key in bytes */ diff --git a/sdk/program/src/log.rs b/sdk/program/src/log.rs index a94db5179a..132a102c0e 100644 --- a/sdk/program/src/log.rs +++ b/sdk/program/src/log.rs @@ -96,3 +96,19 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) { info!("Instruction data"); sol_log_slice(data); } + +/// Logs the current compute unit consumption +#[inline] +pub fn sol_log_compute_units() { + #[cfg(target_arch = "bpf")] + unsafe { + sol_log_compute_units_(); + } + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log_compute_units(); +} + +#[cfg(target_arch = "bpf")] +extern "C" { + fn sol_log_compute_units_(); +} diff --git a/sdk/program/src/program_stubs.rs b/sdk/program/src/program_stubs.rs index 2a858582cd..9e696adab4 100644 --- a/sdk/program/src/program_stubs.rs +++ b/sdk/program/src/program_stubs.rs @@ -19,6 +19,9 @@ pub trait SyscallStubs: Sync + Send { fn sol_log(&self, message: &str) { println!("{}", message); } + fn sol_log_compute_units(&self) { + sol_log("SyscallStubs: sol_log_compute_units() not available"); + } fn sol_invoke_signed( &self, _instruction: &Instruction, @@ -41,6 +44,10 @@ pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) sol_log(&format!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5)); } +pub(crate) fn sol_log_compute_units() { + SYSCALL_STUBS.read().unwrap().sol_log_compute_units(); +} + pub(crate) fn sol_invoke_signed( instruction: &Instruction, account_infos: &[AccountInfo], diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index ddd4359d3c..6e49d59f38 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -86,15 +86,19 @@ macro_rules! declare_name { /// # // wrapper is used so that the macro invocation occurs in the item position /// # // rather than in the statement position which isn't allowed. /// # mod item_wrapper { -/// use solana_sdk::keyed_account::KeyedAccount; -/// use solana_sdk::instruction::InstructionError; -/// use solana_sdk::pubkey::Pubkey; -/// use solana_sdk::declare_program; +/// use solana_sdk::{ +/// declare_program, +/// instruction::InstructionError, +/// keyed_account::KeyedAccount, +/// process_instruction::InvokeContext, +/// pubkey::Pubkey, +/// }; /// /// fn my_process_instruction( /// program_id: &Pubkey, /// keyed_accounts: &[KeyedAccount], /// instruction_data: &[u8], +/// invoke_context: &mut dyn InvokeContext, /// ) -> Result<(), InstructionError> { /// // Process an instruction /// Ok(()) @@ -117,15 +121,19 @@ macro_rules! declare_name { /// # // wrapper is used so that the macro invocation occurs in the item position /// # // rather than in the statement position which isn't allowed. /// # mod item_wrapper { -/// use solana_sdk::keyed_account::KeyedAccount; -/// use solana_sdk::instruction::InstructionError; -/// use solana_sdk::pubkey::Pubkey; -/// use solana_sdk::declare_program; +/// use solana_sdk::{ +/// declare_program, +/// instruction::InstructionError, +/// keyed_account::KeyedAccount, +/// process_instruction::InvokeContext, +/// pubkey::Pubkey, +/// }; /// /// fn my_process_instruction( /// program_id: &Pubkey, /// keyed_accounts: &[KeyedAccount], /// instruction_data: &[u8], +/// invoke_context: &mut dyn InvokeContext, /// ) -> Result<(), InstructionError> { /// // Process an instruction /// Ok(()) @@ -152,8 +160,9 @@ macro_rules! declare_program( program_id: &$crate::pubkey::Pubkey, keyed_accounts: &[$crate::keyed_account::KeyedAccount], instruction_data: &[u8], + invoke_context: &mut dyn $crate::process_instruction::InvokeContext, ) -> Result<(), $crate::instruction::InstructionError> { - $entrypoint(program_id, keyed_accounts, instruction_data) + $entrypoint(program_id, keyed_accounts, instruction_data, invoke_context) } ) ); diff --git a/runtime/src/feature.rs b/sdk/src/feature.rs similarity index 100% rename from runtime/src/feature.rs rename to sdk/src/feature.rs diff --git a/runtime/src/feature_set.rs b/sdk/src/feature_set.rs similarity index 93% rename from runtime/src/feature_set.rs rename to sdk/src/feature_set.rs index c6fca210dc..74265a56f7 100644 --- a/runtime/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -34,7 +34,7 @@ pub mod bpf_loader2_program { solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD"); } -pub mod compute_budget_balancing { +pub mod bpf_compute_budget_balancing { solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB"); } @@ -66,6 +66,10 @@ pub mod cumulative_rent_related_fixes { solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5"); } +pub mod sol_log_compute_units_syscall { + solana_sdk::declare_id!("BHuZqHAj7JdZc68wVgZZcy51jZykvgrx4zptR44RyChe"); +} + pub mod pubkey_log_syscall_enabled { solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN"); } @@ -84,7 +88,7 @@ lazy_static! { (inflation_kill_switch::id(), "inflation kill switch"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (bpf_loader2_program::id(), "bpf_loader2 program"), - (compute_budget_balancing::id(), "compute budget balancing"), + (bpf_compute_budget_balancing::id(), "compute budget balancing"), (sha256_syscall_enabled::id(), "sha256 syscall"), (no_overflow_rent_distribution::id(), "no overflow rent distribution"), (ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"), @@ -92,6 +96,7 @@ lazy_static! { (max_program_call_depth_64::id(), "max program call depth 64"), (timestamp_correction::id(), "correct bank timestamps"), (cumulative_rent_related_fixes::id(), "rent fixes (#10206, #10468, #11342)"), + (sol_log_compute_units_syscall::id(), "sol_log_compute_units syscall (#13243)"), (pubkey_log_syscall_enabled::id(), "pubkey log syscall"), (pull_request_ping_pong_check::id(), "ping-pong packet check #12794"), /*************** ADD NEW FEATURES HERE ***************/ diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 438ea41565..281d1c177a 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -16,6 +16,8 @@ pub mod entrypoint; pub mod entrypoint_deprecated; pub mod entrypoint_native; pub mod epoch_info; +pub mod feature; +pub mod feature_set; pub mod genesis_config; pub mod hard_forks; pub mod hash; @@ -27,6 +29,7 @@ pub mod nonce_account; pub mod nonce_keyed_account; pub mod packet; pub mod poh_config; +pub mod process_instruction; pub mod program_utils; pub mod pubkey; pub mod recent_blockhashes_account; diff --git a/runtime/src/process_instruction.rs b/sdk/src/process_instruction.rs similarity index 60% rename from runtime/src/process_instruction.rs rename to sdk/src/process_instruction.rs index 87089016bd..62647fbad8 100644 --- a/runtime/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -1,9 +1,9 @@ -use crate::feature_set::{ - compute_budget_balancing, max_invoke_depth_4, max_program_call_depth_64, - pubkey_log_syscall_enabled, FeatureSet, -}; use solana_sdk::{ account::Account, + feature_set::{ + bpf_compute_budget_balancing, max_invoke_depth_4, max_program_call_depth_64, + pubkey_log_syscall_enabled, FeatureSet, + }, instruction::{CompiledInstruction, Instruction, InstructionError}, keyed_account::KeyedAccount, message::Message, @@ -24,24 +24,9 @@ pub type LoaderEntrypoint = unsafe extern "C" fn( invoke_context: &dyn InvokeContext, ) -> Result<(), InstructionError>; -pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; pub type ProcessInstructionWithContext = fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; -// These are just type aliases for work around of Debug-ing above function pointers -pub type ErasedProcessInstructionWithContext = fn( - &'static Pubkey, - &'static [KeyedAccount<'static>], - &'static [u8], - &'static mut dyn InvokeContext, -) -> Result<(), InstructionError>; - -pub type ErasedProcessInstruction = fn( - &'static Pubkey, - &'static [KeyedAccount<'static>], - &'static [u8], -) -> Result<(), InstructionError>; - /// Invocation context passed to loaders pub trait InvokeContext { /// Push a program ID on to the invocation stack @@ -58,11 +43,11 @@ pub trait InvokeContext { /// Get the program ID of the currently executing program fn get_caller(&self) -> Result<&Pubkey, InstructionError>; /// Get a list of built-in programs - fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)]; + fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)]; /// Get this invocation's logger fn get_logger(&self) -> Rc>; /// Get this invocation's compute budget - fn get_compute_budget(&self) -> &ComputeBudget; + fn get_bpf_compute_budget(&self) -> &BpfComputeBudget; /// Get this invocation's compute meter fn get_compute_meter(&self) -> Rc>; /// Loaders may need to do work in order to execute a program. Cache @@ -76,8 +61,8 @@ pub trait InvokeContext { fn is_feature_active(&self, feature_id: &Pubkey) -> bool; } -#[derive(Clone, Copy, Debug)] -pub struct ComputeBudget { +#[derive(Clone, Copy, Debug, AbiExample)] +pub struct BpfComputeBudget { /// Number of compute units that an instruction is allowed. Compute units /// are consumed by program execution, resources they use, etc... pub max_units: u64, @@ -103,16 +88,16 @@ pub struct ComputeBudget { /// Number of compute units consumed by logging a `Pubkey` pub log_pubkey_units: u64, } -impl Default for ComputeBudget { +impl Default for BpfComputeBudget { fn default() -> Self { Self::new(&FeatureSet::all_enabled()) } } -impl ComputeBudget { +impl BpfComputeBudget { pub fn new(feature_set: &FeatureSet) -> Self { - let mut compute_budget = + let mut bpf_compute_budget = // Original - ComputeBudget { + BpfComputeBudget { max_units: 100_000, log_units: 0, log_64_units: 0, @@ -126,36 +111,36 @@ impl ComputeBudget { log_pubkey_units: 0, }; - if feature_set.is_active(&compute_budget_balancing::id()) { - compute_budget = ComputeBudget { + if feature_set.is_active(&bpf_compute_budget_balancing::id()) { + bpf_compute_budget = BpfComputeBudget { max_units: 200_000, log_units: 100, log_64_units: 100, create_program_address_units: 1500, invoke_units: 1000, - ..compute_budget + ..bpf_compute_budget }; } if feature_set.is_active(&max_invoke_depth_4::id()) { - compute_budget = ComputeBudget { + bpf_compute_budget = BpfComputeBudget { max_invoke_depth: 4, - ..compute_budget + ..bpf_compute_budget }; } if feature_set.is_active(&max_program_call_depth_64::id()) { - compute_budget = ComputeBudget { + bpf_compute_budget = BpfComputeBudget { max_call_depth: 64, - ..compute_budget + ..bpf_compute_budget }; } if feature_set.is_active(&pubkey_log_syscall_enabled::id()) { - compute_budget = ComputeBudget { + bpf_compute_budget = BpfComputeBudget { log_pubkey_units: 100, - ..compute_budget + ..bpf_compute_budget }; } - compute_budget + bpf_compute_budget } } @@ -185,3 +170,91 @@ pub trait Executor: Debug + Send + Sync { invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError>; } + +#[derive(Debug, Default, Clone)] +pub struct MockComputeMeter { + pub remaining: u64, +} +impl ComputeMeter for MockComputeMeter { + fn consume(&mut self, amount: u64) -> Result<(), InstructionError> { + let exceeded = self.remaining < amount; + self.remaining = self.remaining.saturating_sub(amount); + if exceeded { + return Err(InstructionError::ComputationalBudgetExceeded); + } + Ok(()) + } + fn get_remaining(&self) -> u64 { + self.remaining + } +} + +#[derive(Debug, Default, Clone)] +pub struct MockLogger { + pub log: Rc>>, +} +impl Logger for MockLogger { + fn log_enabled(&self) -> bool { + true + } + fn log(&mut self, message: &str) { + self.log.borrow_mut().push(message.to_string()); + } +} + +#[derive(Debug)] +pub struct MockInvokeContext { + pub key: Pubkey, + pub logger: MockLogger, + pub bpf_compute_budget: BpfComputeBudget, + pub compute_meter: MockComputeMeter, +} +impl Default for MockInvokeContext { + fn default() -> Self { + MockInvokeContext { + key: Pubkey::default(), + logger: MockLogger::default(), + bpf_compute_budget: BpfComputeBudget::default(), + compute_meter: MockComputeMeter { + remaining: std::i64::MAX as u64, + }, + } + } +} +impl InvokeContext for MockInvokeContext { + fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> { + Ok(()) + } + fn pop(&mut self) {} + fn verify_and_update( + &mut self, + _message: &Message, + _instruction: &CompiledInstruction, + _accounts: &[Rc>], + ) -> Result<(), InstructionError> { + Ok(()) + } + fn get_caller(&self) -> Result<&Pubkey, InstructionError> { + Ok(&self.key) + } + fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] { + &[] + } + fn get_logger(&self) -> Rc> { + Rc::new(RefCell::new(self.logger.clone())) + } + fn get_bpf_compute_budget(&self) -> &BpfComputeBudget { + &self.bpf_compute_budget + } + fn get_compute_meter(&self) -> Rc> { + Rc::new(RefCell::new(self.compute_meter.clone())) + } + fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc) {} + fn get_executor(&mut self, _pubkey: &Pubkey) -> Option> { + None + } + fn record_instruction(&self, _instruction: &Instruction) {} + fn is_feature_active(&self, _feature_id: &Pubkey) -> bool { + true + } +} diff --git a/version/Cargo.toml b/version/Cargo.toml index 02a4194704..f4e3835706 100644 --- a/version/Cargo.toml +++ b/version/Cargo.toml @@ -16,7 +16,6 @@ solana-frozen-abi = { path = "../frozen-abi", version = "1.4.4" } solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.4.4" } solana-logger = { path = "../logger", version = "1.4.4" } solana-sdk = { path = "../sdk", version = "1.4.4" } -solana-runtime = { path = "../runtime", version = "1.4.4" } [lib] name = "solana_version" diff --git a/version/src/lib.rs b/version/src/lib.rs index c9b0c3630e..351c765dd4 100644 --- a/version/src/lib.rs +++ b/version/src/lib.rs @@ -51,7 +51,7 @@ fn compute_commit(sha1: Option<&'static str>) -> Option { impl Default for Version { fn default() -> Self { let feature_set = u32::from_le_bytes( - solana_runtime::feature_set::ID.as_ref()[..4] + solana_sdk::feature_set::ID.as_ref()[..4] .try_into() .unwrap(), );