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