Native/builtin programs now receive an InvokeContext (bp #13286) (#13298)

* Native/builtin programs now receive an InvokeContext

(cherry picked from commit df8dab9d2b)

* Remove MessageProcessor::loaders

(cherry picked from commit 2664a1f7ef)

* Remove Entrypoint type

(cherry picked from commit 225bed11c7)

* Remove programs clone()

(cherry picked from commit 33884d847a)

* Add sol_log_compute_units syscall

(cherry picked from commit 66e51a7363)

* Add Bank::set_bpf_compute_budget()

(cherry picked from commit 7d686b72a0)

* Rebase

Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
mergify[bot]
2020-10-30 07:47:17 +00:00
committed by GitHub
parent 36b7c2ea97
commit 40a3885d3b
43 changed files with 631 additions and 477 deletions

3
Cargo.lock generated
View File

@ -3699,7 +3699,6 @@ dependencies = [
"solana-logger 1.4.4", "solana-logger 1.4.4",
"solana-net-utils", "solana-net-utils",
"solana-remote-wallet", "solana-remote-wallet",
"solana-runtime",
"solana-sdk 1.4.4", "solana-sdk 1.4.4",
"solana-stake-program", "solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
@ -4586,6 +4585,7 @@ dependencies = [
"hex", "hex",
"hmac", "hmac",
"itertools 0.9.0", "itertools 0.9.0",
"lazy_static",
"libsecp256k1", "libsecp256k1",
"log 0.4.8", "log 0.4.8",
"memmap", "memmap",
@ -4909,7 +4909,6 @@ dependencies = [
"solana-frozen-abi", "solana-frozen-abi",
"solana-frozen-abi-macro", "solana-frozen-abi-macro",
"solana-logger 1.4.4", "solana-logger 1.4.4",
"solana-runtime",
"solana-sdk 1.4.4", "solana-sdk 1.4.4",
] ]

View File

@ -86,7 +86,7 @@ fn test_exchange_bank_client() {
solana_logger::setup(); solana_logger::setup();
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000); let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
let mut bank = Bank::new(&genesis_config); 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 clients = vec![BankClient::new(bank)];
let mut config = Config::default(); let mut config = Config::default();

View File

@ -39,7 +39,6 @@ solana-logger = { path = "../logger", version = "1.4.4" }
solana-net-utils = { path = "../net-utils", version = "1.4.4" } solana-net-utils = { path = "../net-utils", version = "1.4.4" }
solana_rbpf = "=0.1.32" solana_rbpf = "=0.1.32"
solana-remote-wallet = { path = "../remote-wallet", version = "1.4.4" } 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-sdk = { path = "../sdk", version = "1.4.4" }
solana-stake-program = { path = "../programs/stake", version = "1.4.4" } solana-stake-program = { path = "../programs/stake", version = "1.4.4" }
solana-transaction-status = { path = "../transaction-status", version = "1.4.4" } solana-transaction-status = { path = "../transaction-status", version = "1.4.4" }

View File

@ -9,12 +9,14 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
use solana_cli_output::{QuietDisplay, VerboseDisplay}; use solana_cli_output::{QuietDisplay, VerboseDisplay};
use solana_client::{client_error::ClientError, rpc_client::RpcClient}; use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_runtime::{ use solana_sdk::{
clock::Slot,
feature::{self, Feature}, feature::{self, Feature},
feature_set::FEATURE_NAMES, feature_set::FEATURE_NAMES,
}; message::Message,
use solana_sdk::{ pubkey::Pubkey,
clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction, system_instruction,
transaction::Transaction,
}; };
use std::{collections::HashMap, fmt, sync::Arc}; use std::{collections::HashMap, fmt, sync::Arc};

View File

@ -1,8 +1,8 @@
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
use solana_ledger::blockstore::Blockstore; use solana_ledger::blockstore::Blockstore;
use solana_measure::measure::Measure; use solana_measure::measure::Measure;
use solana_runtime::{bank::Bank, feature_set}; use solana_runtime::bank::Bank;
use solana_sdk::timing::slot_duration_from_slots_per_year; use solana_sdk::{feature_set, timing::slot_duration_from_slots_per_year};
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{ sync::{

View File

@ -52,10 +52,10 @@ use solana_perf::packet::{
}; };
use solana_rayon_threadlimit::get_thread_count; use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::bank_forks::BankForks; use solana_runtime::bank_forks::BankForks;
use solana_runtime::feature_set::{self, FeatureSet};
use solana_sdk::hash::Hash;
use solana_sdk::{ use solana_sdk::{
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH}, clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
feature_set::{self, FeatureSet},
hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signable, Signature, Signer}, signature::{Keypair, Signable, Signature, Signer},
timing::timestamp, timing::timestamp,

View File

@ -1,8 +1,5 @@
use solana_runtime::{ use solana_runtime::bank::{Builtin, Builtins};
bank::{Builtin, Builtins, Entrypoint}, use solana_sdk::{feature_set, genesis_config::ClusterType, pubkey::Pubkey};
feature_set,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
/// Builtin programs that are always available /// Builtin programs that are always available
fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> { fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
@ -19,7 +16,7 @@ fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
builtins builtins
.into_iter() .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() .collect()
} }
@ -32,7 +29,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> {
builtins builtins
.into_iter() .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() .collect()
} }

View File

@ -2211,6 +2211,7 @@ dependencies = [
"hex", "hex",
"hmac", "hmac",
"itertools", "itertools",
"lazy_static",
"libsecp256k1", "libsecp256k1",
"log", "log",
"memmap", "memmap",

View File

@ -11,10 +11,8 @@ use solana_rbpf::vm::{EbpfVm, InstructionMeter};
use solana_runtime::{ use solana_runtime::{
bank::Bank, bank::Bank,
bank_client::BankClient, bank_client::BankClient,
bpf_test_utils::MockInvokeContext,
genesis_utils::{create_genesis_config, GenesisConfigInfo}, genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program, loader_utils::load_program,
process_instruction::{ComputeMeter, InvokeContext},
}; };
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
@ -23,6 +21,7 @@ use solana_sdk::{
entrypoint::SUCCESS, entrypoint::SUCCESS,
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction},
message::Message, message::Message,
process_instruction::{ComputeMeter, InvokeContext, MockInvokeContext},
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
}; };
@ -161,7 +160,7 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
} = create_genesis_config(50); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank); let bank_client = BankClient::new_shared(&bank);

View File

@ -18,5 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
// program, no account keys or input data are expected but real // program, no account keys or input data are expected but real
// programs will have specific requirements so they can do their work. // programs will have specific requirements so they can do their work.
sol_log_params(&params); sol_log_params(&params);
sol_log_compute_units();
return SUCCESS; return SUCCESS;
} }

View File

@ -61,6 +61,7 @@ fn process_instruction(
panic!(); panic!();
} }
sol_log_compute_units();
Ok(()) Ok(())
} }

View File

@ -11,10 +11,8 @@ use solana_rbpf::vm::EbpfVm;
use solana_runtime::{ use solana_runtime::{
bank::Bank, bank::Bank,
bank_client::BankClient, bank_client::BankClient,
bpf_test_utils::MockInvokeContext,
genesis_utils::{create_genesis_config, GenesisConfigInfo}, genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program, loader_utils::load_program,
process_instruction::ComputeBudget,
}; };
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
@ -25,6 +23,7 @@ use solana_sdk::{
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
message::Message, message::Message,
process_instruction::{BpfComputeBudget, MockInvokeContext},
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
sysvar::{clock, fees, rent, slot_hashes, stake_history}, sysvar::{clock, fees, rent, slot_hashes, stake_history},
@ -179,7 +178,7 @@ fn test_program_bpf_sanity() {
} = create_genesis_config(50); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 = Arc::new(bank);
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test // 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); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!(); 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 bank_client = BankClient::new(bank);
let program_id = load_bpf_program( let program_id = load_bpf_program(
@ -273,7 +272,7 @@ fn test_program_bpf_duplicate_accounts() {
} = create_genesis_config(50); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank); let bank_client = BankClient::new_shared(&bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program); 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); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 bank_client = BankClient::new(bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program); let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)]; let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
@ -475,7 +474,7 @@ fn test_program_bpf_invoke() {
} = create_genesis_config(50); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank); let bank_client = BankClient::new_shared(&bank);
@ -706,7 +705,7 @@ fn test_program_bpf_call_depth() {
} = create_genesis_config(50); } = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 bank_client = BankClient::new(bank);
let program_id = load_bpf_program( let program_id = load_bpf_program(
&bank_client, &bank_client,
@ -717,14 +716,14 @@ fn test_program_bpf_call_depth() {
let instruction = Instruction::new( let instruction = Instruction::new(
program_id, program_id,
&(ComputeBudget::default().max_call_depth - 1), &(BpfComputeBudget::default().max_call_depth - 1),
vec![], vec![],
); );
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_ok()); assert!(result.is_ok());
let instruction = 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); let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_err()); assert!(result.is_err());
} }
@ -788,7 +787,7 @@ fn test_program_bpf_instruction_introspection() {
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!(); 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 = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank); let bank_client = BankClient::new_shared(&bank);

View File

@ -16,17 +16,15 @@ use solana_rbpf::{
memory_region::MemoryRegion, memory_region::MemoryRegion,
vm::{Config, EbpfVm, Executable, InstructionMeter}, vm::{Config, EbpfVm, Executable, InstructionMeter},
}; };
use solana_runtime::{
feature_set::compute_budget_balancing,
process_instruction::{ComputeMeter, Executor, InvokeContext},
};
use solana_sdk::{ use solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
decode_error::DecodeError, decode_error::DecodeError,
entrypoint::SUCCESS, entrypoint::SUCCESS,
feature_set::bpf_compute_budget_balancing,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{is_executable, next_keyed_account, KeyedAccount}, keyed_account::{is_executable, next_keyed_account, KeyedAccount},
loader_instruction::LoaderInstruction, loader_instruction::LoaderInstruction,
process_instruction::{ComputeMeter, Executor, InvokeContext},
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
}; };
@ -101,7 +99,7 @@ pub fn create_and_cache_executor(
.map_err(|e| map_ebpf_error(invoke_context, e))?; .map_err(|e| map_ebpf_error(invoke_context, e))?;
bpf_verifier::check( bpf_verifier::check(
elf_bytes, 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)))?; .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
let executor = Arc::new(BPFExecutor { executable }); let executor = Arc::new(BPFExecutor { executable });
@ -116,12 +114,12 @@ pub fn create_vm<'a>(
parameter_accounts: &'a [KeyedAccount<'a>], parameter_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext, invoke_context: &'a mut dyn InvokeContext,
) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError<BPFError>> { ) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError<BPFError>> {
let compute_budget = invoke_context.get_compute_budget(); let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
let mut vm = EbpfVm::new( let mut vm = EbpfVm::new(
executable, executable,
Config { Config {
max_call_depth: compute_budget.max_call_depth, max_call_depth: bpf_compute_budget.max_call_depth,
stack_frame_size: compute_budget.stack_frame_size, stack_frame_size: bpf_compute_budget.stack_frame_size,
}, },
)?; )?;
let heap_region = let heap_region =
@ -312,13 +310,14 @@ impl Executor for BPFExecutor {
mod tests { mod tests {
use super::*; use super::*;
use rand::Rng; use rand::Rng;
use solana_runtime::{ use solana_runtime::message_processor::{Executors, ThisInvokeContext};
bpf_test_utils::MockInvokeContext, use solana_sdk::{
account::Account,
feature_set::FeatureSet, feature_set::FeatureSet,
message_processor::{Executors, ThisInvokeContext}, instruction::InstructionError,
process_instruction::ComputeBudget, 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}; use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
struct TestInstructionMeter { struct TestInstructionMeter {
@ -533,9 +532,9 @@ mod tests {
&program_id, &program_id,
Rent::default(), Rent::default(),
vec![], vec![],
vec![], &[],
None, None,
ComputeBudget { BpfComputeBudget {
max_units: 1, max_units: 1,
log_units: 100, log_units: 100,
log_64_units: 100, log_64_units: 100,

View File

@ -7,22 +7,21 @@ use solana_rbpf::{
memory_region::{translate_addr, MemoryRegion}, memory_region::{translate_addr, MemoryRegion},
vm::{EbpfVm, SyscallObject}, vm::{EbpfVm, SyscallObject},
}; };
use solana_runtime::{ use solana_runtime::message_processor::MessageProcessor;
feature_set::{
pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled,
},
message_processor::MessageProcessor,
process_instruction::{ComputeMeter, InvokeContext, Logger},
};
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
account_info::AccountInfo, account_info::AccountInfo,
bpf_loader, bpf_loader_deprecated, bpf_loader_deprecated,
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, 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}, hash::{Hasher, HASH_BYTES},
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
message::Message, message::Message,
process_instruction::{ComputeMeter, InvokeContext, Logger},
program_error::ProgramError, program_error::ProgramError,
pubkey::{Pubkey, PubkeyError}, pubkey::{Pubkey, PubkeyError},
}; };
@ -98,7 +97,7 @@ pub fn register_syscalls<'a>(
callers_keyed_accounts: &'a [KeyedAccount<'a>], callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext, invoke_context: &'a mut dyn InvokeContext,
) -> Result<MemoryRegion, EbpfError<BPFError>> { ) -> Result<MemoryRegion, EbpfError<BPFError>> {
let compute_budget = invoke_context.get_compute_budget(); let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
// Syscall functions common across languages // Syscall functions common across languages
@ -107,7 +106,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_log_", "sol_log_",
Box::new(SyscallLog { Box::new(SyscallLog {
cost: compute_budget.log_units, cost: bpf_compute_budget.log_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
loader_id, loader_id,
@ -116,17 +115,27 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_log_64_", "sol_log_64_",
Box::new(SyscallLogU64 { Box::new(SyscallLogU64 {
cost: compute_budget.log_64_units, cost: bpf_compute_budget.log_64_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
}), }),
)?; )?;
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()) { if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) {
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_log_pubkey", "sol_log_pubkey",
Box::new(SyscallLogPubkey { Box::new(SyscallLogPubkey {
cost: compute_budget.log_pubkey_units, cost: bpf_compute_budget.log_pubkey_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(), logger: invoke_context.get_logger(),
loader_id, loader_id,
@ -138,8 +147,8 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_sha256", "sol_sha256",
Box::new(SyscallSha256 { Box::new(SyscallSha256 {
sha256_base_cost: compute_budget.sha256_base_cost, sha256_base_cost: bpf_compute_budget.sha256_base_cost,
sha256_byte_cost: compute_budget.sha256_byte_cost, sha256_byte_cost: bpf_compute_budget.sha256_byte_cost,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
loader_id, loader_id,
}), }),
@ -160,7 +169,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex( vm.register_syscall_with_context_ex(
"sol_create_program_address", "sol_create_program_address",
Box::new(SyscallCreateProgramAddress { Box::new(SyscallCreateProgramAddress {
cost: compute_budget.create_program_address_units, cost: bpf_compute_budget.create_program_address_units,
compute_meter: invoke_context.get_compute_meter(), compute_meter: invoke_context.get_compute_meter(),
loader_id, loader_id,
}), }),
@ -414,6 +423,38 @@ impl SyscallObject<BPFError> for SyscallLogU64 {
} }
} }
/// Log current compute consumption
pub struct SyscallLogBpfComputeUnits {
cost: u64,
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
logger: Rc<RefCell<dyn Logger>>,
}
impl SyscallObject<BPFError> for SyscallLogBpfComputeUnits {
fn call(
&mut self,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
_ro_regions: &[MemoryRegion],
_rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> {
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 /// Log 5 64-bit values
pub struct SyscallLogPubkey<'a> { pub struct SyscallLogPubkey<'a> {
cost: u64, cost: u64,
@ -1147,7 +1188,7 @@ fn call<'a>(
let mut invoke_context = syscall.get_context_mut()?; let mut invoke_context = syscall.get_context_mut()?;
invoke_context invoke_context
.get_compute_meter() .get_compute_meter()
.consume(invoke_context.get_compute_budget().invoke_units)?; .consume(invoke_context.get_bpf_compute_budget().invoke_units)?;
// Translate data passed from the VM // Translate data passed from the VM
@ -1185,8 +1226,6 @@ fn call<'a>(
for (program_id, process_instruction) in invoke_context.get_programs().iter() { for (program_id, process_instruction) in invoke_context.get_programs().iter() {
message_processor.add_program(*program_id, *process_instruction); 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)] #[allow(clippy::deref_addrof)]
match message_processor.process_cross_program_instruction( match message_processor.process_cross_program_instruction(
@ -1237,8 +1276,11 @@ fn call<'a>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_runtime::bpf_test_utils::{MockComputeMeter, MockLogger}; use solana_sdk::{
use solana_sdk::hash::hashv; bpf_loader,
hash::hashv,
process_instruction::{MockComputeMeter, MockLogger},
};
use std::str::FromStr; use std::str::FromStr;
macro_rules! assert_access_violation { macro_rules! assert_access_violation {

View File

@ -10,6 +10,7 @@ use solana_sdk::{
hash::hash, hash::hash,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount}, keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
}; };
@ -116,6 +117,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter(); let keyed_accounts_iter = &mut keyed_accounts.iter();
let instruction = limited_deserialize(data)?; let instruction = limited_deserialize(data)?;
@ -238,7 +240,7 @@ mod tests {
fn create_bank(lamports: u64) -> (Bank, Keypair) { fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports); let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config); 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) (bank, mint_keypair)
} }

View File

@ -3,15 +3,19 @@
use crate::ConfigKeys; use crate::ConfigKeys;
use bincode::deserialize; use bincode::deserialize;
use log::*; use log::*;
use solana_sdk::instruction::InstructionError; use solana_sdk::{
use solana_sdk::keyed_account::{next_keyed_account, KeyedAccount}; instruction::InstructionError,
use solana_sdk::program_utils::limited_deserialize; keyed_account::{next_keyed_account, KeyedAccount},
use solana_sdk::pubkey::Pubkey; process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
pub fn process_instruction( pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let key_list: ConfigKeys = limited_deserialize(data)?; let key_list: ConfigKeys = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter(); let keyed_accounts_iter = &mut keyed_accounts.iter();
@ -109,6 +113,7 @@ mod tests {
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
keyed_account::create_keyed_is_signer_accounts, keyed_account::create_keyed_is_signer_accounts,
process_instruction::MockInvokeContext,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction::SystemInstruction, system_instruction::SystemInstruction,
}; };
@ -162,7 +167,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)]; let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instructions[1].data), process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
@ -192,7 +202,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)]; let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
assert_eq!( assert_eq!(
@ -214,7 +229,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)]; let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidInstructionData) Err(InstructionError::InvalidInstructionData)
); );
} }
@ -232,7 +252,12 @@ mod tests {
let accounts = vec![(&config_pubkey, false, &config_account)]; let accounts = vec![(&config_pubkey, false, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
} }
@ -262,7 +287,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); 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 accounts = vec![(&signer0_pubkey, true, &signer0_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidAccountData) Err(InstructionError::InvalidAccountData)
); );
} }
@ -314,7 +349,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
@ -325,7 +365,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
} }
@ -357,7 +402,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
@ -372,7 +422,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); 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); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
@ -410,7 +470,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
} }
@ -443,7 +508,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
@ -457,7 +527,12 @@ mod tests {
]; ];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(()) Ok(())
); );
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap(); 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 accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data), process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
} }
@ -487,7 +567,12 @@ mod tests {
let accounts = vec![]; let accounts = vec![];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts); let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!( assert_eq!(
process_instruction(&id(), &keyed_accounts, &instructions[1].data), process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys) Err(InstructionError::NotEnoughAccountKeys)
); );
} }

View File

@ -9,7 +9,7 @@ use serde_derive::Serialize;
use solana_metrics::inc_new_counter_info; use solana_metrics::inc_new_counter_info;
use solana_sdk::{ use solana_sdk::{
decode_error::DecodeError, instruction::InstructionError, keyed_account::KeyedAccount, 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 std::cmp;
use thiserror::Error; use thiserror::Error;
@ -464,6 +464,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
solana_logger::setup(); solana_logger::setup();
@ -578,7 +579,7 @@ mod test {
fn create_bank(lamports: u64) -> (Bank, Keypair) { fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports); let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config); 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) (bank, mint_keypair)
} }

View File

@ -1,6 +1,7 @@
use solana_sdk::instruction::InstructionError; use solana_sdk::{
use solana_sdk::keyed_account::KeyedAccount; instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
use solana_sdk::pubkey::Pubkey; pubkey::Pubkey,
};
solana_sdk::declare_program!( solana_sdk::declare_program!(
"FaiLure111111111111111111111111111111111111", "FaiLure111111111111111111111111111111111111",
@ -12,6 +13,7 @@ fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
Err(InstructionError::Custom(0)) Err(InstructionError::Custom(0))
} }

View File

@ -1,7 +1,8 @@
use log::*; use log::*;
use solana_sdk::instruction::InstructionError; use solana_sdk::{
use solana_sdk::keyed_account::KeyedAccount; instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
use solana_sdk::pubkey::Pubkey; pubkey::Pubkey,
};
solana_sdk::declare_program!( solana_sdk::declare_program!(
"Noop111111111111111111111111111111111111111", "Noop111111111111111111111111111111111111111",
@ -13,6 +14,7 @@ fn process_instruction(
program_id: &Pubkey, program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
solana_logger::setup(); solana_logger::setup();
trace!("noop: program_id: {:?}", program_id); trace!("noop: program_id: {:?}", program_id);

View File

@ -5,6 +5,7 @@ use bincode::serialize_into;
use solana_sdk::{ use solana_sdk::{
instruction::InstructionError, instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount}, keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
}; };
@ -30,6 +31,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let new_owner_pubkey: Pubkey = limited_deserialize(data)?; let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter(); let keyed_accounts_iter = &mut keyed_accounts.iter();
@ -71,7 +73,7 @@ mod tests {
fn create_bank(lamports: u64) -> (Bank, Keypair) { fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports); let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config); 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) (bank, mint_keypair)
} }

View File

@ -1,24 +1,20 @@
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{ use solana_sdk::{
instruction::{Instruction, InstructionError}, instruction::{Instruction, InstructionError},
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
process_instruction::InvokeContext,
pubkey::Pubkey,
}; };
pub fn process_instruction( pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// Should be already checked by now. // Should be already checked by now.
Ok(()) Ok(())
} }
solana_sdk::declare_program!(
solana_sdk::secp256k1_program::ID,
solana_keccak_secp256k1_program,
process_instruction
);
pub fn new_secp256k1_instruction( pub fn new_secp256k1_instruction(
priv_key: &secp256k1::SecretKey, priv_key: &secp256k1::SecretKey,
message_arr: &[u8], message_arr: &[u8],

View File

@ -10,6 +10,7 @@ use solana_sdk::{
decode_error::DecodeError, decode_error::DecodeError,
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
system_instruction, system_instruction,
@ -446,6 +447,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
trace!("process_instruction: {:?}", data); trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts); trace!("keyed_accounts: {:?}", keyed_accounts);
@ -525,6 +527,7 @@ mod tests {
use bincode::serialize; use bincode::serialize;
use solana_sdk::{ use solana_sdk::{
account::{self, Account}, account::{self, Account},
process_instruction::MockInvokeContext,
rent::Rent, rent::Rent,
sysvar::stake_history::StakeHistory, sysvar::stake_history::StakeHistory,
}; };
@ -562,7 +565,12 @@ mod tests {
.zip(accounts.iter()) .zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect(); .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() Lockup::default()
)) ))
.unwrap(), .unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
@ -679,6 +688,7 @@ mod tests {
Lockup::default() Lockup::default()
)) ))
.unwrap(), .unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
@ -696,6 +706,7 @@ mod tests {
Lockup::default() Lockup::default()
)) ))
.unwrap(), .unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::InvalidArgument), Err(InstructionError::InvalidArgument),
); );
@ -717,6 +728,7 @@ mod tests {
Lockup::default() Lockup::default()
)) ))
.unwrap(), .unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
@ -731,6 +743,7 @@ mod tests {
&create_default_account() &create_default_account()
),], ),],
&serialize(&StakeInstruction::DelegateStake).unwrap(), &serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
@ -745,6 +758,7 @@ mod tests {
&create_default_account() &create_default_account()
)], )],
&serialize(&StakeInstruction::DelegateStake).unwrap(), &serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
@ -776,6 +790,7 @@ mod tests {
), ),
], ],
&serialize(&StakeInstruction::DelegateStake).unwrap(), &serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
@ -802,6 +817,7 @@ mod tests {
), ),
], ],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(), &serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::InvalidArgument), Err(InstructionError::InvalidArgument),
); );
@ -816,6 +832,7 @@ mod tests {
&create_default_account() &create_default_account()
)], )],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(), &serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
@ -836,6 +853,7 @@ mod tests {
), ),
], ],
&serialize(&StakeInstruction::Deactivate).unwrap(), &serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::InvalidArgument), Err(InstructionError::InvalidArgument),
); );
@ -846,6 +864,7 @@ mod tests {
&Pubkey::default(), &Pubkey::default(),
&[], &[],
&serialize(&StakeInstruction::Deactivate).unwrap(), &serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
), ),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );

View File

@ -10,6 +10,7 @@ use solana_sdk::{
account::Account, account::Account,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount}, keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
}; };
@ -59,6 +60,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter(); let keyed_accounts_iter = &mut keyed_accounts.iter();
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?; 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) { fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports); let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config); 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) (bank, mint_keypair)
} }

View File

@ -14,6 +14,7 @@ use solana_sdk::{
hash::Hash, hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
system_instruction, system_instruction,
@ -277,6 +278,7 @@ pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
trace!("process_instruction: {:?}", data); trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts); trace!("keyed_accounts: {:?}", keyed_accounts);
@ -333,6 +335,7 @@ mod tests {
use super::*; use super::*;
use solana_sdk::{ use solana_sdk::{
account::{self, Account}, account::{self, Account},
process_instruction::MockInvokeContext,
rent::Rent, rent::Rent,
}; };
use std::cell::RefCell; use std::cell::RefCell;
@ -341,7 +344,12 @@ mod tests {
#[test] #[test]
fn test_vote_process_instruction_decode_bail() { fn test_vote_process_instruction_decode_bail() {
assert_eq!( assert_eq!(
super::process_instruction(&Pubkey::default(), &[], &[],), super::process_instruction(
&Pubkey::default(),
&[],
&[],
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
} }
@ -374,7 +382,12 @@ mod tests {
.zip(accounts.iter()) .zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect(); .collect();
super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data) super::process_instruction(
&Pubkey::default(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default(),
)
} }
} }

View File

@ -12,6 +12,7 @@ use solana_sdk::{
instruction::InstructionError, instruction::InstructionError,
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
message::Message, message::Message,
process_instruction::InvokeContext,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
transaction::Transaction, transaction::Transaction,
@ -33,6 +34,7 @@ fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
Ok(()) Ok(())
} }
@ -123,7 +125,7 @@ fn do_bench_transactions(
let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000); let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000);
genesis_config.ticks_per_slot = 100; genesis_config.ticks_per_slot = 100;
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program( bank.add_builtin(
"builtin_program", "builtin_program",
Pubkey::new(&BUILTIN_PROGRAM_ID), Pubkey::new(&BUILTIN_PROGRAM_ID),
process_instruction, process_instruction,

View File

@ -17,10 +17,6 @@ use crate::{
instruction_recorder::InstructionRecorder, instruction_recorder::InstructionRecorder,
log_collector::LogCollector, log_collector::LogCollector,
message_processor::{Executors, MessageProcessor}, message_processor::{Executors, MessageProcessor},
process_instruction::{
ErasedProcessInstruction, ErasedProcessInstructionWithContext, Executor,
ProcessInstruction, ProcessInstructionWithContext,
},
rent_collector::RentCollector, rent_collector::RentCollector,
stakes::Stakes, stakes::Stakes,
status_cache::{SlotDelta, StatusCache}, status_cache::{SlotDelta, StatusCache},
@ -55,6 +51,7 @@ use solana_sdk::{
native_loader, native_loader,
native_token::sol_to_lamports, native_token::sol_to_lamports,
nonce, nonce_account, nonce, nonce_account,
process_instruction::{BpfComputeBudget, Executor, ProcessInstructionWithContext},
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
recent_blockhashes_account, recent_blockhashes_account,
@ -138,52 +135,33 @@ type RentCollectionCycleParams = (
type EpochCount = u64; type EpochCount = u64;
#[derive(Copy, Clone)] #[derive(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)]
pub struct Builtin { pub struct Builtin {
pub name: String, pub name: String,
pub id: Pubkey, pub id: Pubkey,
pub entrypoint: Entrypoint, pub process_instruction_with_context: ProcessInstructionWithContext,
} }
impl Builtin { 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 { Self {
name: name.to_string(), name: name.to_string(),
id, 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 /// Copy-on-write holder of CachedExecutors
#[derive(AbiExample, Debug, Default)] #[derive(AbiExample, Debug, Default)]
struct CowCachedExecutors { struct CowCachedExecutors {
@ -224,7 +202,7 @@ impl AbiExample for Builtin {
Self { Self {
name: String::default(), name: String::default(),
id: Pubkey::default(), id: Pubkey::default(),
entrypoint: Entrypoint::Program(|_, _, _| Ok(())), process_instruction_with_context: |_, _, _, _| Ok(()),
} }
} }
} }
@ -693,6 +671,8 @@ pub struct Bank {
/// The Message processor /// The Message processor
message_processor: MessageProcessor, message_processor: MessageProcessor,
bpf_compute_budget: Option<BpfComputeBudget>,
/// Builtin programs activated dynamically by feature /// Builtin programs activated dynamically by feature
feature_builtins: Arc<Vec<(Builtin, Pubkey)>>, feature_builtins: Arc<Vec<(Builtin, Pubkey)>>,
@ -829,6 +809,7 @@ impl Bank {
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)), tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
signature_count: AtomicU64::new(0), signature_count: AtomicU64::new(0),
message_processor: parent.message_processor.clone(), message_processor: parent.message_processor.clone(),
bpf_compute_budget: parent.bpf_compute_budget,
feature_builtins: parent.feature_builtins.clone(), feature_builtins: parent.feature_builtins.clone(),
hard_forks: parent.hard_forks.clone(), hard_forks: parent.hard_forks.clone(),
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)), last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
@ -934,6 +915,7 @@ impl Bank {
epoch_stakes: fields.epoch_stakes, epoch_stakes: fields.epoch_stakes,
is_delta: AtomicBool::new(fields.is_delta), is_delta: AtomicBool::new(fields.is_delta),
message_processor: new(), message_processor: new(),
bpf_compute_budget: None,
feature_builtins: new(), feature_builtins: new(),
last_vote_sync: new(), last_vote_sync: new(),
rewards: new(), rewards: new(),
@ -2375,6 +2357,9 @@ impl Bank {
let mut inner_instructions: Vec<Option<InnerInstructionsList>> = let mut inner_instructions: Vec<Option<InnerInstructionsList>> =
Vec::with_capacity(txs.len()); Vec::with_capacity(txs.len());
let mut transaction_logs: Vec<TransactionLogMessages> = Vec::with_capacity(txs.len()); let mut transaction_logs: Vec<TransactionLogMessages> = Vec::with_capacity(txs.len());
let bpf_compute_budget = self
.bpf_compute_budget
.unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set));
let executed: Vec<TransactionProcessResult> = loaded_accounts let executed: Vec<TransactionProcessResult> = loaded_accounts
.iter_mut() .iter_mut()
@ -2413,6 +2398,7 @@ impl Bank {
executors.clone(), executors.clone(),
instruction_recorders.as_deref(), instruction_recorders.as_deref(),
self.feature_set.clone(), self.feature_set.clone(),
bpf_compute_budget,
); );
if enable_log_recording { if enable_log_recording {
@ -3365,7 +3351,11 @@ impl Bank {
.extend_from_slice(&additional_builtins.feature_builtins); .extend_from_slice(&additional_builtins.feature_builtins);
} }
for builtin in builtins.genesis_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); self.feature_builtins = Arc::new(builtins.feature_builtins);
@ -3376,6 +3366,10 @@ impl Bank {
*self.inflation.write().unwrap() = inflation; *self.inflation.write().unwrap() = inflation;
} }
pub fn set_bpf_compute_budget(&mut self, bpf_compute_budget: Option<BpfComputeBudget>) {
self.bpf_compute_budget = bpf_compute_budget;
}
pub fn hard_forks(&self) -> Arc<RwLock<HardForks>> { pub fn hard_forks(&self) -> Arc<RwLock<HardForks>> {
self.hard_forks.clone() self.hard_forks.clone()
} }
@ -3823,43 +3817,17 @@ impl Bank {
!self.is_delta.load(Relaxed) !self.is_delta.load(Relaxed)
} }
pub fn add_builtin_program( /// Add an instruction processor to intercept instructions before the dynamic loader.
&mut self, pub fn add_builtin(
name: &str,
program_id: Pubkey,
process_instruction: ProcessInstruction,
) {
self.add_builtin(name, program_id, Entrypoint::Program(process_instruction));
}
pub fn add_builtin_loader(
&mut self, &mut self,
name: &str, name: &str,
program_id: Pubkey, program_id: Pubkey,
process_instruction_with_context: ProcessInstructionWithContext, process_instruction_with_context: ProcessInstructionWithContext,
) { ) {
self.add_builtin( debug!("Added program {} under {:?}", name, program_id);
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) {
self.add_native_program(name, &program_id); self.add_native_program(name, &program_id);
match entrypoint {
Entrypoint::Program(process_instruction) => {
self.message_processor self.message_processor
.add_program(program_id, process_instruction); .add_program(program_id, process_instruction_with_context);
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);
}
}
} }
pub fn clean_accounts(&self, skip_last: bool) { 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) let should_populate = init_or_warp && self.feature_set.is_active(&feature)
|| !init_or_warp && new_feature_activations.contains(&feature); || !init_or_warp && new_feature_activations.contains(&feature);
if should_populate { 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, BOOTSTRAP_VALIDATOR_LAMPORTS,
}, },
native_loader::NativeLoaderError, native_loader::NativeLoaderError,
process_instruction::InvokeContext,
status_cache::MAX_CACHE_ENTRIES, status_cache::MAX_CACHE_ENTRIES,
}; };
use solana_sdk::{ use solana_sdk::{
@ -4138,6 +4109,7 @@ mod tests {
message::{Message, MessageHeader}, message::{Message, MessageHeader},
nonce, nonce,
poh_config::PohConfig, poh_config::PohConfig,
process_instruction::InvokeContext,
rent::Rent, rent::Rent,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction::{self, SystemError}, system_instruction::{self, SystemError},
@ -4428,6 +4400,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> { ) -> result::Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) { if let Ok(instruction) = bincode::deserialize(data) {
match instruction { match instruction {
@ -4577,7 +4550,7 @@ mod tests {
) as u64, ) as u64,
); );
bank.rent_collector.slots_per_year = 421_812.0; 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 bank
} }
@ -7713,7 +7686,7 @@ mod tests {
} }
#[test] #[test]
fn test_add_builtin_program() { fn test_add_builtin() {
let (genesis_config, mint_keypair) = create_genesis_config(500); let (genesis_config, mint_keypair) = create_genesis_config(500);
let mut bank = Bank::new(&genesis_config); let mut bank = Bank::new(&genesis_config);
@ -7724,6 +7697,7 @@ mod tests {
program_id: &Pubkey, program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_instruction_data: &[u8], _instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> { ) -> std::result::Result<(), InstructionError> {
if mock_vote_program_id() != *program_id { if mock_vote_program_id() != *program_id {
return Err(InstructionError::IncorrectProgramId); return Err(InstructionError::IncorrectProgramId);
@ -7732,7 +7706,7 @@ mod tests {
} }
assert!(bank.get_account(&mock_vote_program_id()).is_none()); assert!(bank.get_account(&mock_vote_program_id()).is_none());
bank.add_builtin_program( bank.add_builtin(
"mock_vote_program", "mock_vote_program",
mock_vote_program_id(), mock_vote_program_id(),
mock_vote_processor, mock_vote_processor,
@ -7781,6 +7755,7 @@ mod tests {
_pubkey: &Pubkey, _pubkey: &Pubkey,
_ka: &[KeyedAccount], _ka: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> { ) -> std::result::Result<(), InstructionError> {
Err(InstructionError::Custom(42)) Err(InstructionError::Custom(42))
} }
@ -7805,7 +7780,7 @@ mod tests {
); );
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap(); 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",
solana_vote_program::id(), solana_vote_program::id(),
mock_vote_processor, mock_vote_processor,
@ -7831,6 +7806,7 @@ mod tests {
_pubkey: &Pubkey, _pubkey: &Pubkey,
_ka: &[KeyedAccount], _ka: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> { ) -> std::result::Result<(), InstructionError> {
Err(InstructionError::Custom(42)) Err(InstructionError::Custom(42))
} }
@ -7850,15 +7826,15 @@ mod tests {
assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty()); assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization()); assert_eq!(bank.calculate_capitalization(), bank.capitalization());
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor); bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin_program("mock_program2", stake_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().vote_accounts().is_empty());
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty()); assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization()); assert_eq!(bank.calculate_capitalization(), bank.capitalization());
// Re-adding builtin programs should be no-op // Re-adding builtin programs should be no-op
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor); bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin_program("mock_program2", stake_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().vote_accounts().is_empty());
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty()); assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization()); assert_eq!(bank.calculate_capitalization(), bank.capitalization());
@ -8499,6 +8475,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> { ) -> result::Result<(), InstructionError> {
let lamports = data[0] as u64; let lamports = data[0] as u64;
{ {
@ -8513,7 +8490,7 @@ mod tests {
} }
let mock_program_id = Pubkey::new(&[2u8; 32]); 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 from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand(); let to_pubkey = solana_sdk::pubkey::new_rand();
@ -8551,12 +8528,13 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> { ) -> result::Result<(), InstructionError> {
Ok(()) Ok(())
} }
let mock_program_id = Pubkey::new(&[2u8; 32]); 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 from_pubkey = solana_sdk::pubkey::new_rand();
let to_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()); tx.message.account_keys.push(solana_sdk::pubkey::new_rand());
bank.add_builtin_program( bank.add_builtin(
"mock_vote", "mock_vote",
solana_vote_program::id(), solana_vote_program::id(),
mock_ok_vote_processor, mock_ok_vote_processor,
@ -8662,7 +8640,7 @@ mod tests {
AccountMeta::new(to_pubkey, false), AccountMeta::new(to_pubkey, false),
]; ];
bank.add_builtin_program( bank.add_builtin(
"mock_vote", "mock_vote",
solana_vote_program::id(), solana_vote_program::id(),
mock_ok_vote_processor, mock_ok_vote_processor,
@ -8695,7 +8673,7 @@ mod tests {
AccountMeta::new(to_pubkey, false), AccountMeta::new(to_pubkey, false),
]; ];
bank.add_builtin_program( bank.add_builtin(
"mock_vote", "mock_vote",
solana_vote_program::id(), solana_vote_program::id(),
mock_ok_vote_processor, mock_ok_vote_processor,
@ -8733,6 +8711,7 @@ mod tests {
_pubkey: &Pubkey, _pubkey: &Pubkey,
_ka: &[KeyedAccount], _ka: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> { ) -> std::result::Result<(), InstructionError> {
Ok(()) Ok(())
} }
@ -8750,7 +8729,7 @@ mod tests {
AccountMeta::new(to_pubkey, false), AccountMeta::new(to_pubkey, false),
]; ];
bank.add_builtin_program( bank.add_builtin(
"mock_vote", "mock_vote",
solana_vote_program::id(), solana_vote_program::id(),
mock_ok_vote_processor, mock_ok_vote_processor,
@ -8786,7 +8765,7 @@ mod tests {
.map(|i| { .map(|i| {
let key = solana_sdk::pubkey::new_rand(); let key = solana_sdk::pubkey::new_rand();
let name = format!("program{:?}", i); 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()) (key, name.as_bytes().to_vec())
}) })
.collect(); .collect();
@ -8981,6 +8960,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> { ) -> result::Result<(), InstructionError> {
assert_eq!(42, keyed_accounts[0].lamports().unwrap()); assert_eq!(42, keyed_accounts[0].lamports().unwrap());
let mut account = keyed_accounts[0].try_account_ref_mut()?; let mut account = keyed_accounts[0].try_account_ref_mut()?;
@ -8993,7 +8973,7 @@ mod tests {
// Add a new program // Add a new program
let program1_pubkey = solana_sdk::pubkey::new_rand(); 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 // Add a new program owned by the first
let program2_pubkey = solana_sdk::pubkey::new_rand(); let program2_pubkey = solana_sdk::pubkey::new_rand();
@ -9155,13 +9135,14 @@ mod tests {
} }
#[test] #[test]
fn test_add_builtin_program_no_overwrite() { fn test_add_builtin_no_overwrite() {
let (genesis_config, _mint_keypair) = create_genesis_config(100_000); let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
fn mock_ix_processor( fn mock_ix_processor(
_pubkey: &Pubkey, _pubkey: &Pubkey,
_ka: &[KeyedAccount], _ka: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> { ) -> std::result::Result<(), InstructionError> {
Ok(()) Ok(())
} }
@ -9176,19 +9157,15 @@ mod tests {
)); ));
assert_eq!(bank.get_account_modified_slot(&program_id), None); assert_eq!(bank.get_account_modified_slot(&program_id), None);
Arc::get_mut(&mut bank).unwrap().add_builtin_program( Arc::get_mut(&mut bank)
"mock_program", .unwrap()
program_id, .add_builtin("mock_program", program_id, mock_ix_processor);
mock_ix_processor,
);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank)); let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank).unwrap().add_builtin_program( Arc::get_mut(&mut bank)
"mock_program", .unwrap()
program_id, .add_builtin("mock_program", program_id, mock_ix_processor);
mock_ix_processor,
);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); 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); assert_eq!(bank.get_account_modified_slot(&loader_id), None);
Arc::get_mut(&mut bank).unwrap().add_builtin_loader( Arc::get_mut(&mut bank)
"mock_program", .unwrap()
loader_id, .add_builtin("mock_program", loader_id, mock_ix_processor);
mock_ix_processor,
);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank)); let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank).unwrap().add_builtin_loader( Arc::get_mut(&mut bank)
"mock_program", .unwrap()
loader_id, .add_builtin("mock_program", loader_id, mock_ix_processor);
mock_ix_processor,
);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
} }
@ -10061,25 +10034,4 @@ mod tests {
let debug = format!("{:#?}", bank); let debug = format!("{:#?}", bank);
assert!(!debug.is_empty()); 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());
}
} }

View File

@ -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<RefCell<Vec<String>>>,
}
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<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone()))
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
bank::{Builtin, Builtins, Entrypoint}, bank::{Builtin, Builtins},
feature_set, system_instruction_processor, feature_set, system_instruction_processor,
}; };
use solana_sdk::{pubkey::Pubkey, system_program}; use solana_sdk::{pubkey::Pubkey, system_program};
@ -10,22 +10,22 @@ fn genesis_builtins() -> Vec<Builtin> {
Builtin::new( Builtin::new(
"system_program", "system_program",
system_program::id(), system_program::id(),
Entrypoint::Program(system_instruction_processor::process_instruction), system_instruction_processor::process_instruction,
), ),
Builtin::new( Builtin::new(
"vote_program", "vote_program",
solana_vote_program::id(), solana_vote_program::id(),
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction), solana_vote_program::vote_instruction::process_instruction,
), ),
Builtin::new( Builtin::new(
"stake_program", "stake_program",
solana_stake_program::id(), solana_stake_program::id(),
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction), solana_stake_program::stake_instruction::process_instruction,
), ),
Builtin::new( Builtin::new(
"config_program", "config_program",
solana_config_program::id(), 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( Builtin::new(
"secp256k1_program", "secp256k1_program",
solana_sdk::secp256k1_program::id(), solana_sdk::secp256k1_program::id(),
Entrypoint::Program(solana_secp256k1_program::process_instruction), solana_secp256k1_program::process_instruction,
), ),
feature_set::secp256k1_program_enabled::id(), feature_set::secp256k1_program_enabled::id(),
)] )]

View File

@ -10,12 +10,9 @@ pub mod bank_forks;
pub mod bank_utils; pub mod bank_utils;
mod blockhash_queue; mod blockhash_queue;
pub mod bloom; pub mod bloom;
pub mod bpf_test_utils;
pub mod builtins; pub mod builtins;
pub mod commitment; pub mod commitment;
pub mod epoch_stakes; pub mod epoch_stakes;
pub mod feature;
pub mod feature_set;
pub mod genesis_utils; pub mod genesis_utils;
pub mod hardened_unpack; pub mod hardened_unpack;
pub mod instruction_recorder; pub mod instruction_recorder;
@ -23,7 +20,6 @@ pub mod loader_utils;
pub mod log_collector; pub mod log_collector;
pub mod message_processor; pub mod message_processor;
mod native_loader; mod native_loader;
pub mod process_instruction;
pub mod rent_collector; pub mod rent_collector;
pub mod serde_snapshot; pub mod serde_snapshot;
pub mod snapshot_package; pub mod snapshot_package;
@ -35,6 +31,10 @@ pub mod transaction_batch;
pub mod transaction_utils; pub mod transaction_utils;
pub mod vote_sender_types; 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_config_program;
extern crate solana_stake_program; extern crate solana_stake_program;
extern crate solana_vote_program; extern crate solana_vote_program;

View File

@ -3,10 +3,6 @@ use crate::{
instruction_recorder::InstructionRecorder, instruction_recorder::InstructionRecorder,
log_collector::LogCollector, log_collector::LogCollector,
native_loader::NativeLoader, native_loader::NativeLoader,
process_instruction::{
ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
},
rent_collector::RentCollector, rent_collector::RentCollector,
}; };
use log::*; use log::*;
@ -18,6 +14,10 @@ use solana_sdk::{
keyed_account::{create_keyed_readonly_accounts, KeyedAccount}, keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
message::Message, message::Message,
native_loader, native_loader,
process_instruction::{
BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger,
ProcessInstructionWithContext,
},
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
system_program, system_program,
@ -201,31 +201,31 @@ impl ComputeMeter for ThisComputeMeter {
self.remaining self.remaining
} }
} }
pub struct ThisInvokeContext { pub struct ThisInvokeContext<'a> {
program_ids: Vec<Pubkey>, program_ids: Vec<Pubkey>,
rent: Rent, rent: Rent,
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>, programs: &'a [(Pubkey, ProcessInstructionWithContext)],
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
compute_budget: ComputeBudget, bpf_compute_budget: BpfComputeBudget,
compute_meter: Rc<RefCell<dyn ComputeMeter>>, compute_meter: Rc<RefCell<dyn ComputeMeter>>,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>, feature_set: Arc<FeatureSet>,
} }
impl ThisInvokeContext { impl<'a> ThisInvokeContext<'a> {
pub fn new( pub fn new(
program_id: &Pubkey, program_id: &Pubkey,
rent: Rent, rent: Rent,
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>, programs: &'a [(Pubkey, ProcessInstructionWithContext)],
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
compute_budget: ComputeBudget, bpf_compute_budget: BpfComputeBudget,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>, feature_set: Arc<FeatureSet>,
) -> Self { ) -> Self {
let mut program_ids = Vec::with_capacity(compute_budget.max_invoke_depth); let mut program_ids = Vec::with_capacity(bpf_compute_budget.max_invoke_depth);
program_ids.push(*program_id); program_ids.push(*program_id);
Self { Self {
program_ids, program_ids,
@ -233,9 +233,9 @@ impl ThisInvokeContext {
pre_accounts, pre_accounts,
programs, programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })), logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
compute_budget, bpf_compute_budget,
compute_meter: Rc::new(RefCell::new(ThisComputeMeter { compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
remaining: compute_budget.max_units, remaining: bpf_compute_budget.max_units,
})), })),
executors, executors,
instruction_recorder, 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> { 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); return Err(InstructionError::CallDepth);
} }
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) { if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
@ -281,14 +281,14 @@ impl InvokeContext for ThisInvokeContext {
.last() .last()
.ok_or(InstructionError::GenericError) .ok_or(InstructionError::GenericError)
} }
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] { fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
&self.programs self.programs
} }
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> { fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
self.logger.clone() self.logger.clone()
} }
fn get_compute_budget(&self) -> &ComputeBudget { fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
&self.compute_budget &self.bpf_compute_budget
} }
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> { fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
self.compute_meter.clone() self.compute_meter.clone()
@ -326,9 +326,7 @@ impl Logger for ThisLogger {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct MessageProcessor { pub struct MessageProcessor {
#[serde(skip)] #[serde(skip)]
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
#[serde(skip)]
loaders: Vec<(Pubkey, ProcessInstructionWithContext)>,
#[serde(skip)] #[serde(skip)]
native_loader: NativeLoader, native_loader: NativeLoader,
} }
@ -338,9 +336,17 @@ impl std::fmt::Debug for MessageProcessor {
#[derive(Debug)] #[derive(Debug)]
struct MessageProcessor<'a> { struct MessageProcessor<'a> {
programs: Vec<String>, programs: Vec<String>,
loaders: Vec<String>,
native_loader: &'a NativeLoader, 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 // rustc doesn't compile due to bug without this work around
// https://github.com/rust-lang/rust/issues/50280 // https://github.com/rust-lang/rust/issues/50280
// https://users.rust-lang.org/t/display-function-pointer/17073/2 // https://users.rust-lang.org/t/display-function-pointer/17073/2
@ -348,14 +354,6 @@ impl std::fmt::Debug for MessageProcessor {
programs: self programs: self
.programs .programs
.iter() .iter()
.map(|(pubkey, instruction)| {
let erased_instruction: ErasedProcessInstruction = *instruction;
format!("{}: {:p}", pubkey, erased_instruction)
})
.collect::<Vec<_>>(),
loaders: self
.loaders
.iter()
.map(|(pubkey, instruction)| { .map(|(pubkey, instruction)| {
let erased_instruction: ErasedProcessInstructionWithContext = *instruction; let erased_instruction: ErasedProcessInstructionWithContext = *instruction;
format!("{}: {:p}", pubkey, erased_instruction) format!("{}: {:p}", pubkey, erased_instruction)
@ -372,7 +370,6 @@ impl Default for MessageProcessor {
fn default() -> Self { fn default() -> Self {
Self { Self {
programs: vec![], programs: vec![],
loaders: vec![],
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
} }
} }
@ -381,7 +378,6 @@ impl Clone for MessageProcessor {
fn clone(&self) -> Self { fn clone(&self) -> Self {
MessageProcessor { MessageProcessor {
programs: self.programs.clone(), programs: self.programs.clone(),
loaders: self.loaders.clone(),
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
} }
} }
@ -398,7 +394,11 @@ impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
impl MessageProcessor { impl MessageProcessor {
/// Add a static entrypoint to intercept instructions before the dynamic loader. /// 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) { match self.programs.iter_mut().find(|(key, _)| program_id == *key) {
Some((_, processor)) => *processor = process_instruction, Some((_, processor)) => *processor = process_instruction,
None => self.programs.push((program_id, process_instruction)), None => self.programs.push((program_id, process_instruction)),
@ -410,14 +410,7 @@ impl MessageProcessor {
program_id: Pubkey, program_id: Pubkey,
process_instruction: ProcessInstructionWithContext, process_instruction: ProcessInstructionWithContext,
) { ) {
match self.loaders.iter_mut().find(|(key, _)| program_id == *key) { self.add_program(program_id, process_instruction);
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)
} }
/// Create the KeyedAccounts that will be passed to the program /// 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 let Some(root_account) = keyed_accounts.iter().next() {
if native_loader::check_id(&root_account.owner()?) { if native_loader::check_id(&root_account.owner()?) {
let root_id = root_account.unsigned_key(); 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 { for (id, process_instruction) in &self.programs {
if id == root_id { if id == root_id {
// Call the builtin program // Call the builtin program
@ -476,6 +458,7 @@ impl MessageProcessor {
&root_id, &root_id,
&keyed_accounts[1..], &keyed_accounts[1..],
instruction_data, instruction_data,
invoke_context,
); );
} }
} }
@ -488,7 +471,7 @@ impl MessageProcessor {
); );
} else { } else {
let owner_id = &root_account.owner()?; let owner_id = &root_account.owner()?;
for (id, process_instruction) in &self.loaders { for (id, process_instruction) in &self.programs {
if id == owner_id { if id == owner_id {
// Call the program via a builtin loader // Call the program via a builtin loader
return process_instruction( return process_instruction(
@ -667,6 +650,7 @@ impl MessageProcessor {
instruction_recorder: Option<InstructionRecorder>, instruction_recorder: Option<InstructionRecorder>,
instruction_index: usize, instruction_index: usize,
feature_set: Arc<FeatureSet>, feature_set: Arc<FeatureSet>,
bpf_compute_budget: BpfComputeBudget,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// Fixup the special instructions key if present // Fixup the special instructions key if present
// before the account pre-values are taken care of // before the account pre-values are taken care of
@ -688,9 +672,9 @@ impl MessageProcessor {
instruction.program_id(&message.account_keys), instruction.program_id(&message.account_keys),
rent_collector.rent, rent_collector.rent,
pre_accounts, pre_accounts,
self.programs.clone(), // get rid of clone &self.programs,
log_collector, log_collector,
Self::get_compute_budget(&feature_set), bpf_compute_budget,
executors, executors,
instruction_recorder, instruction_recorder,
feature_set, feature_set,
@ -723,6 +707,7 @@ impl MessageProcessor {
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
instruction_recorders: Option<&[InstructionRecorder]>, instruction_recorders: Option<&[InstructionRecorder]>,
feature_set: Arc<FeatureSet>, feature_set: Arc<FeatureSet>,
bpf_compute_budget: BpfComputeBudget,
) -> Result<(), TransactionError> { ) -> Result<(), TransactionError> {
for (instruction_index, instruction) in message.instructions.iter().enumerate() { for (instruction_index, instruction) in message.instructions.iter().enumerate() {
let instruction_recorder = instruction_recorders let instruction_recorder = instruction_recorders
@ -739,6 +724,7 @@ impl MessageProcessor {
instruction_recorder, instruction_recorder,
instruction_index, instruction_index,
feature_set.clone(), feature_set.clone(),
bpf_compute_budget,
) )
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?; .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
} }
@ -781,9 +767,9 @@ mod tests {
&program_ids[0], &program_ids[0],
Rent::default(), Rent::default(),
pre_accounts, pre_accounts,
vec![], &[],
None, None,
ComputeBudget::default(), BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
@ -1266,6 +1252,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) { if let Ok(instruction) = bincode::deserialize(data) {
match instruction { match instruction {
@ -1327,6 +1314,7 @@ mod tests {
executors.clone(), executors.clone(),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 100); assert_eq!(accounts[0].borrow().lamports, 100);
@ -1350,6 +1338,7 @@ mod tests {
executors.clone(), executors.clone(),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1377,6 +1366,7 @@ mod tests {
executors, executors,
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1400,6 +1390,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) { if let Ok(instruction) = bincode::deserialize(data) {
match instruction { match instruction {
@ -1487,6 +1478,7 @@ mod tests {
executors.clone(), executors.clone(),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!( assert_eq!(
result, result,
@ -1514,6 +1506,7 @@ mod tests {
executors.clone(), executors.clone(),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
@ -1538,6 +1531,7 @@ mod tests {
executors, executors,
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 80); assert_eq!(accounts[0].borrow().lamports, 80);
@ -1559,6 +1553,7 @@ mod tests {
program_id: &Pubkey, program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
assert_eq!(*program_id, keyed_accounts[0].owner()?); assert_eq!(*program_id, keyed_accounts[0].owner()?);
assert_ne!( assert_ne!(
@ -1609,9 +1604,9 @@ mod tests {
&caller_program_id, &caller_program_id,
Rent::default(), Rent::default(),
vec![owned_preaccount, not_owned_preaccount], vec![owned_preaccount, not_owned_preaccount],
vec![], &[],
None, None,
ComputeBudget::default(), BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,
Arc::new(FeatureSet::all_enabled()), Arc::new(FeatureSet::all_enabled()),
@ -1675,6 +1670,7 @@ mod tests {
_program_id: &Pubkey, _program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount], _keyed_accounts: &[KeyedAccount],
_data: &[u8], _data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
Ok(()) Ok(())
} }

View File

@ -1,5 +1,4 @@
//! Native loader //! Native loader
use crate::process_instruction::{InvokeContext, LoaderEntrypoint};
#[cfg(unix)] #[cfg(unix)]
use libloading::os::unix::*; use libloading::os::unix::*;
#[cfg(windows)] #[cfg(windows)]
@ -11,6 +10,7 @@ use solana_sdk::{
entrypoint_native::ProgramEntrypoint, entrypoint_native::ProgramEntrypoint,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount}, keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::{InvokeContext, LoaderEntrypoint},
pubkey::Pubkey, pubkey::Pubkey,
}; };
use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock}; use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock};

View File

@ -6,6 +6,7 @@ use solana_sdk::{
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
nonce, nonce,
nonce_keyed_account::NonceKeyedAccount, nonce_keyed_account::NonceKeyedAccount,
process_instruction::InvokeContext,
program_utils::limited_deserialize, program_utils::limited_deserialize,
pubkey::Pubkey, pubkey::Pubkey,
system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH}, system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
@ -213,6 +214,7 @@ pub fn process_instruction(
_owner: &Pubkey, _owner: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
instruction_data: &[u8], instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let instruction = limited_deserialize(instruction_data)?; let instruction = limited_deserialize(instruction_data)?;
@ -363,7 +365,9 @@ mod tests {
hash::{hash, Hash}, hash::{hash, Hash},
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
message::Message, message::Message,
nonce, nonce_account, recent_blockhashes_account, nonce, nonce_account,
process_instruction::MockInvokeContext,
recent_blockhashes_account,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction, system_program, sysvar, system_instruction, system_program, sysvar,
sysvar::recent_blockhashes::IterItem, 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<Account> { fn create_default_account() -> RefCell<Account> {
RefCell::new(Account::default()) RefCell::new(Account::default())
} }
@ -1194,7 +1211,7 @@ mod tests {
.zip(accounts.iter()) .zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account)) .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect(); .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] #[test]
fn test_process_nonce_ix_no_keyed_accs_fail() { fn test_process_nonce_ix_no_keyed_accs_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[], &[],
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap() &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
@ -1224,7 +1241,7 @@ mod tests {
#[test] #[test]
fn test_process_nonce_ix_only_nonce_acc_fail() { fn test_process_nonce_ix_only_nonce_acc_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
@ -1240,7 +1257,7 @@ mod tests {
#[test] #[test]
fn test_process_nonce_ix_bad_recent_blockhash_state_fail() { fn test_process_nonce_ix_bad_recent_blockhash_state_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()), KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
@ -1259,7 +1276,7 @@ mod tests {
#[test] #[test]
fn test_process_nonce_ix_ok() { fn test_process_nonce_ix_ok() {
let nonce_acc = nonce_account::create_account(1_000_000); let nonce_acc = nonce_account::create_account(1_000_000);
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc), KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
@ -1288,7 +1305,7 @@ mod tests {
), ),
); );
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,), KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),
@ -1320,7 +1337,7 @@ mod tests {
#[test] #[test]
fn test_process_withdraw_ix_no_keyed_accs_fail() { fn test_process_withdraw_ix_no_keyed_accs_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[], &[],
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
@ -1332,7 +1349,7 @@ mod tests {
#[test] #[test]
fn test_process_withdraw_ix_only_nonce_acc_fail() { fn test_process_withdraw_ix_only_nonce_acc_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
@ -1348,7 +1365,7 @@ mod tests {
#[test] #[test]
fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() { fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()), KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
@ -1368,7 +1385,7 @@ mod tests {
#[test] #[test]
fn test_process_withdraw_ix_bad_rent_state_fail() { fn test_process_withdraw_ix_bad_rent_state_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new( KeyedAccount::new(
@ -1393,7 +1410,7 @@ mod tests {
#[test] #[test]
fn test_process_withdraw_ix_ok() { fn test_process_withdraw_ix_ok() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new( KeyedAccount::new(
@ -1418,7 +1435,7 @@ mod tests {
#[test] #[test]
fn test_process_initialize_ix_no_keyed_accs_fail() { fn test_process_initialize_ix_no_keyed_accs_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[], &[],
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
@ -1430,7 +1447,7 @@ mod tests {
#[test] #[test]
fn test_process_initialize_ix_only_nonce_acc_fail() { fn test_process_initialize_ix_only_nonce_acc_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
@ -1446,7 +1463,7 @@ mod tests {
#[test] #[test]
fn test_process_initialize_bad_recent_blockhash_state_fail() { fn test_process_initialize_bad_recent_blockhash_state_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new( KeyedAccount::new(
@ -1469,7 +1486,7 @@ mod tests {
#[test] #[test]
fn test_process_initialize_ix_bad_rent_state_fail() { fn test_process_initialize_ix_bad_rent_state_fail() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new( KeyedAccount::new(
@ -1493,7 +1510,7 @@ mod tests {
#[test] #[test]
fn test_process_initialize_ix_ok() { fn test_process_initialize_ix_ok() {
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new( KeyedAccount::new(
@ -1517,7 +1534,7 @@ mod tests {
#[test] #[test]
fn test_process_authorize_ix_ok() { fn test_process_authorize_ix_ok() {
let nonce_acc = nonce_account::create_account(1_000_000); let nonce_acc = nonce_account::create_account(1_000_000);
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc), KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
@ -1532,7 +1549,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
super::process_instruction( process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),], &[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(), &serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),

View File

@ -46,6 +46,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser
hex = "0.4.2" hex = "0.4.2"
hmac = "0.7.0" hmac = "0.7.0"
itertools = "0.9.0" itertools = "0.9.0"
lazy_static = "1.4.0"
log = "0.4.8" log = "0.4.8"
memmap = { version = "0.7.0", optional = true } memmap = { version = "0.7.0", optional = true }
num-derive = "0.3" num-derive = "0.3"

View File

@ -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); void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
#define sol_log_64 sol_log_64_ #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 * Size of Public key in bytes
*/ */

View File

@ -96,3 +96,19 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
info!("Instruction data"); info!("Instruction data");
sol_log_slice(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_();
}

View File

@ -19,6 +19,9 @@ pub trait SyscallStubs: Sync + Send {
fn sol_log(&self, message: &str) { fn sol_log(&self, message: &str) {
println!("{}", message); println!("{}", message);
} }
fn sol_log_compute_units(&self) {
sol_log("SyscallStubs: sol_log_compute_units() not available");
}
fn sol_invoke_signed( fn sol_invoke_signed(
&self, &self,
_instruction: &Instruction, _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)); 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( pub(crate) fn sol_invoke_signed(
instruction: &Instruction, instruction: &Instruction,
account_infos: &[AccountInfo], account_infos: &[AccountInfo],

View File

@ -86,15 +86,19 @@ macro_rules! declare_name {
/// # // wrapper is used so that the macro invocation occurs in the item position /// # // wrapper is used so that the macro invocation occurs in the item position
/// # // rather than in the statement position which isn't allowed. /// # // rather than in the statement position which isn't allowed.
/// # mod item_wrapper { /// # mod item_wrapper {
/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::{
/// use solana_sdk::instruction::InstructionError; /// declare_program,
/// use solana_sdk::pubkey::Pubkey; /// instruction::InstructionError,
/// use solana_sdk::declare_program; /// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
/// ///
/// fn my_process_instruction( /// fn my_process_instruction(
/// program_id: &Pubkey, /// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount], /// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8], /// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> { /// ) -> Result<(), InstructionError> {
/// // Process an instruction /// // Process an instruction
/// Ok(()) /// Ok(())
@ -117,15 +121,19 @@ macro_rules! declare_name {
/// # // wrapper is used so that the macro invocation occurs in the item position /// # // wrapper is used so that the macro invocation occurs in the item position
/// # // rather than in the statement position which isn't allowed. /// # // rather than in the statement position which isn't allowed.
/// # mod item_wrapper { /// # mod item_wrapper {
/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::{
/// use solana_sdk::instruction::InstructionError; /// declare_program,
/// use solana_sdk::pubkey::Pubkey; /// instruction::InstructionError,
/// use solana_sdk::declare_program; /// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
/// ///
/// fn my_process_instruction( /// fn my_process_instruction(
/// program_id: &Pubkey, /// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount], /// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8], /// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> { /// ) -> Result<(), InstructionError> {
/// // Process an instruction /// // Process an instruction
/// Ok(()) /// Ok(())
@ -152,8 +160,9 @@ macro_rules! declare_program(
program_id: &$crate::pubkey::Pubkey, program_id: &$crate::pubkey::Pubkey,
keyed_accounts: &[$crate::keyed_account::KeyedAccount], keyed_accounts: &[$crate::keyed_account::KeyedAccount],
instruction_data: &[u8], instruction_data: &[u8],
invoke_context: &mut dyn $crate::process_instruction::InvokeContext,
) -> Result<(), $crate::instruction::InstructionError> { ) -> Result<(), $crate::instruction::InstructionError> {
$entrypoint(program_id, keyed_accounts, instruction_data) $entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
} }
) )
); );

View File

@ -34,7 +34,7 @@ pub mod bpf_loader2_program {
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD"); solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
} }
pub mod compute_budget_balancing { pub mod bpf_compute_budget_balancing {
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB"); solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
} }
@ -66,6 +66,10 @@ pub mod cumulative_rent_related_fixes {
solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5"); solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5");
} }
pub mod sol_log_compute_units_syscall {
solana_sdk::declare_id!("BHuZqHAj7JdZc68wVgZZcy51jZykvgrx4zptR44RyChe");
}
pub mod pubkey_log_syscall_enabled { pub mod pubkey_log_syscall_enabled {
solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN"); solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN");
} }
@ -84,7 +88,7 @@ lazy_static! {
(inflation_kill_switch::id(), "inflation kill switch"), (inflation_kill_switch::id(), "inflation kill switch"),
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
(bpf_loader2_program::id(), "bpf_loader2 program"), (bpf_loader2_program::id(), "bpf_loader2 program"),
(compute_budget_balancing::id(), "compute budget balancing"), (bpf_compute_budget_balancing::id(), "compute budget balancing"),
(sha256_syscall_enabled::id(), "sha256 syscall"), (sha256_syscall_enabled::id(), "sha256 syscall"),
(no_overflow_rent_distribution::id(), "no overflow rent distribution"), (no_overflow_rent_distribution::id(), "no overflow rent distribution"),
(ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"), (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"), (max_program_call_depth_64::id(), "max program call depth 64"),
(timestamp_correction::id(), "correct bank timestamps"), (timestamp_correction::id(), "correct bank timestamps"),
(cumulative_rent_related_fixes::id(), "rent fixes (#10206, #10468, #11342)"), (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"), (pubkey_log_syscall_enabled::id(), "pubkey log syscall"),
(pull_request_ping_pong_check::id(), "ping-pong packet check #12794"), (pull_request_ping_pong_check::id(), "ping-pong packet check #12794"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/

View File

@ -16,6 +16,8 @@ pub mod entrypoint;
pub mod entrypoint_deprecated; pub mod entrypoint_deprecated;
pub mod entrypoint_native; pub mod entrypoint_native;
pub mod epoch_info; pub mod epoch_info;
pub mod feature;
pub mod feature_set;
pub mod genesis_config; pub mod genesis_config;
pub mod hard_forks; pub mod hard_forks;
pub mod hash; pub mod hash;
@ -27,6 +29,7 @@ pub mod nonce_account;
pub mod nonce_keyed_account; pub mod nonce_keyed_account;
pub mod packet; pub mod packet;
pub mod poh_config; pub mod poh_config;
pub mod process_instruction;
pub mod program_utils; pub mod program_utils;
pub mod pubkey; pub mod pubkey;
pub mod recent_blockhashes_account; pub mod recent_blockhashes_account;

View File

@ -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::{ use solana_sdk::{
account::Account, 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}, instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
message::Message, message::Message,
@ -24,24 +24,9 @@ pub type LoaderEntrypoint = unsafe extern "C" fn(
invoke_context: &dyn InvokeContext, invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
pub type ProcessInstructionWithContext = pub type ProcessInstructionWithContext =
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; 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 /// Invocation context passed to loaders
pub trait InvokeContext { pub trait InvokeContext {
/// Push a program ID on to the invocation stack /// 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 /// Get the program ID of the currently executing program
fn get_caller(&self) -> Result<&Pubkey, InstructionError>; fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
/// Get a list of built-in programs /// Get a list of built-in programs
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)]; fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)];
/// Get this invocation's logger /// Get this invocation's logger
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>; fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
/// Get this invocation's compute budget /// 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 /// Get this invocation's compute meter
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>; fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
/// Loaders may need to do work in order to execute a program. Cache /// Loaders may need to do work in order to execute a program. Cache
@ -76,8 +61,8 @@ pub trait InvokeContext {
fn is_feature_active(&self, feature_id: &Pubkey) -> bool; fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, AbiExample)]
pub struct ComputeBudget { pub struct BpfComputeBudget {
/// Number of compute units that an instruction is allowed. Compute units /// Number of compute units that an instruction is allowed. Compute units
/// are consumed by program execution, resources they use, etc... /// are consumed by program execution, resources they use, etc...
pub max_units: u64, pub max_units: u64,
@ -103,16 +88,16 @@ pub struct ComputeBudget {
/// Number of compute units consumed by logging a `Pubkey` /// Number of compute units consumed by logging a `Pubkey`
pub log_pubkey_units: u64, pub log_pubkey_units: u64,
} }
impl Default for ComputeBudget { impl Default for BpfComputeBudget {
fn default() -> Self { fn default() -> Self {
Self::new(&FeatureSet::all_enabled()) Self::new(&FeatureSet::all_enabled())
} }
} }
impl ComputeBudget { impl BpfComputeBudget {
pub fn new(feature_set: &FeatureSet) -> Self { pub fn new(feature_set: &FeatureSet) -> Self {
let mut compute_budget = let mut bpf_compute_budget =
// Original // Original
ComputeBudget { BpfComputeBudget {
max_units: 100_000, max_units: 100_000,
log_units: 0, log_units: 0,
log_64_units: 0, log_64_units: 0,
@ -126,36 +111,36 @@ impl ComputeBudget {
log_pubkey_units: 0, log_pubkey_units: 0,
}; };
if feature_set.is_active(&compute_budget_balancing::id()) { if feature_set.is_active(&bpf_compute_budget_balancing::id()) {
compute_budget = ComputeBudget { bpf_compute_budget = BpfComputeBudget {
max_units: 200_000, max_units: 200_000,
log_units: 100, log_units: 100,
log_64_units: 100, log_64_units: 100,
create_program_address_units: 1500, create_program_address_units: 1500,
invoke_units: 1000, invoke_units: 1000,
..compute_budget ..bpf_compute_budget
}; };
} }
if feature_set.is_active(&max_invoke_depth_4::id()) { if feature_set.is_active(&max_invoke_depth_4::id()) {
compute_budget = ComputeBudget { bpf_compute_budget = BpfComputeBudget {
max_invoke_depth: 4, max_invoke_depth: 4,
..compute_budget ..bpf_compute_budget
}; };
} }
if feature_set.is_active(&max_program_call_depth_64::id()) { if feature_set.is_active(&max_program_call_depth_64::id()) {
compute_budget = ComputeBudget { bpf_compute_budget = BpfComputeBudget {
max_call_depth: 64, max_call_depth: 64,
..compute_budget ..bpf_compute_budget
}; };
} }
if feature_set.is_active(&pubkey_log_syscall_enabled::id()) { if feature_set.is_active(&pubkey_log_syscall_enabled::id()) {
compute_budget = ComputeBudget { bpf_compute_budget = BpfComputeBudget {
log_pubkey_units: 100, 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, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> 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<RefCell<Vec<String>>>,
}
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<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
&self.bpf_compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone()))
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}

View File

@ -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-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.4.4" }
solana-logger = { path = "../logger", version = "1.4.4" } solana-logger = { path = "../logger", version = "1.4.4" }
solana-sdk = { path = "../sdk", version = "1.4.4" } solana-sdk = { path = "../sdk", version = "1.4.4" }
solana-runtime = { path = "../runtime", version = "1.4.4" }
[lib] [lib]
name = "solana_version" name = "solana_version"

View File

@ -51,7 +51,7 @@ fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
impl Default for Version { impl Default for Version {
fn default() -> Self { fn default() -> Self {
let feature_set = u32::from_le_bytes( 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() .try_into()
.unwrap(), .unwrap(),
); );