Bump solana_rbpf to v0.8.0 (#33679)
* Bumps solana_rbpf to v0.8.0 * Adjustments: Replaces declare_syscall!() with declare_builtin_function!(). Removes Config::encrypt_runtime_environment. Simplifies error propagation.
This commit is contained in:
parent
dc3c827299
commit
a5c7c999e2
|
@ -6640,6 +6640,7 @@ dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
|
"solana_rbpf",
|
||||||
"test-case",
|
"test-case",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -7625,9 +7626,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.7.2"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196"
|
checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -378,7 +378,7 @@ solana-wen-restart = { path = "wen-restart", version = "=1.18.0" }
|
||||||
solana-zk-keygen = { path = "zk-keygen", version = "=1.18.0" }
|
solana-zk-keygen = { path = "zk-keygen", version = "=1.18.0" }
|
||||||
solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.18.0" }
|
solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.18.0" }
|
||||||
solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.18.0" }
|
solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.18.0" }
|
||||||
solana_rbpf = "=0.7.2"
|
solana_rbpf = "=0.8.0"
|
||||||
spl-associated-token-account = "=2.2.0"
|
spl-associated-token-account = "=2.2.0"
|
||||||
spl-instruction-padding = "0.1"
|
spl-instruction-padding = "0.1"
|
||||||
spl-memo = "=4.0.0"
|
spl-memo = "=4.0.0"
|
||||||
|
|
|
@ -2994,7 +2994,7 @@ pub mod tests {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(mock_processor_ok, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltinOk, 1, |_invoke_context| {
|
||||||
// Always succeeds
|
// Always succeeds
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
@ -3002,7 +3002,7 @@ pub mod tests {
|
||||||
let mock_program_id = solana_sdk::pubkey::new_rand();
|
let mock_program_id = solana_sdk::pubkey::new_rand();
|
||||||
|
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_processor_ok);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltinOk::vm);
|
||||||
|
|
||||||
let tx = Transaction::new_signed_with_payer(
|
let tx = Transaction::new_signed_with_payer(
|
||||||
&[Instruction::new_with_bincode(
|
&[Instruction::new_with_bincode(
|
||||||
|
@ -3023,7 +3023,7 @@ pub mod tests {
|
||||||
let bankhash_ok = bank.hash();
|
let bankhash_ok = bank.hash();
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
declare_process_instruction!(mock_processor_err, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltinErr, 1, |invoke_context| {
|
||||||
let instruction_errors = get_instruction_errors();
|
let instruction_errors = get_instruction_errors();
|
||||||
|
|
||||||
let err = invoke_context
|
let err = invoke_context
|
||||||
|
@ -3043,7 +3043,7 @@ pub mod tests {
|
||||||
|
|
||||||
(0..get_instruction_errors().len()).for_each(|err| {
|
(0..get_instruction_errors().len()).for_each(|err| {
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_processor_err);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltinErr::vm);
|
||||||
|
|
||||||
let tx = Transaction::new_signed_with_payer(
|
let tx = Transaction::new_signed_with_payer(
|
||||||
&[Instruction::new_with_bincode(
|
&[Instruction::new_with_bincode(
|
||||||
|
|
|
@ -12,9 +12,10 @@ use {
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
ebpf::MM_HEAP_START,
|
ebpf::MM_HEAP_START,
|
||||||
elf::SBPFVersion,
|
error::{EbpfError, ProgramResult},
|
||||||
memory_region::MemoryMapping,
|
memory_region::MemoryMapping,
|
||||||
vm::{BuiltinFunction, Config, ContextObject, ProgramResult},
|
program::{BuiltinFunction, SBPFVersion},
|
||||||
|
vm::{Config, ContextObject, EbpfVm},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::AccountSharedData,
|
account::AccountSharedData,
|
||||||
|
@ -39,44 +40,46 @@ use {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ProcessInstructionWithContext = BuiltinFunction<InvokeContext<'static>>;
|
pub type BuiltinFunctionWithContext = BuiltinFunction<InvokeContext<'static>>;
|
||||||
|
|
||||||
/// Adapter so we can unify the interfaces of built-in programs and syscalls
|
/// Adapter so we can unify the interfaces of built-in programs and syscalls
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! declare_process_instruction {
|
macro_rules! declare_process_instruction {
|
||||||
($process_instruction:ident, $cu_to_consume:expr, |$invoke_context:ident| $inner:tt) => {
|
($process_instruction:ident, $cu_to_consume:expr, |$invoke_context:ident| $inner:tt) => {
|
||||||
pub fn $process_instruction(
|
$crate::solana_rbpf::declare_builtin_function!(
|
||||||
invoke_context: &mut $crate::invoke_context::InvokeContext,
|
$process_instruction,
|
||||||
_arg0: u64,
|
fn rust(
|
||||||
_arg1: u64,
|
invoke_context: &mut $crate::invoke_context::InvokeContext,
|
||||||
_arg2: u64,
|
_arg0: u64,
|
||||||
_arg3: u64,
|
_arg1: u64,
|
||||||
_arg4: u64,
|
_arg2: u64,
|
||||||
_memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping,
|
_arg3: u64,
|
||||||
result: &mut $crate::solana_rbpf::vm::ProgramResult,
|
_arg4: u64,
|
||||||
) {
|
_memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping,
|
||||||
fn process_instruction_inner(
|
) -> std::result::Result<u64, Box<dyn std::error::Error>> {
|
||||||
$invoke_context: &mut $crate::invoke_context::InvokeContext,
|
fn process_instruction_inner(
|
||||||
) -> std::result::Result<(), solana_sdk::instruction::InstructionError> {
|
$invoke_context: &mut $crate::invoke_context::InvokeContext,
|
||||||
$inner
|
) -> std::result::Result<(), solana_sdk::instruction::InstructionError> {
|
||||||
|
$inner
|
||||||
|
}
|
||||||
|
let consumption_result = if $cu_to_consume > 0
|
||||||
|
&& invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&solana_sdk::feature_set::native_programs_consume_cu::id())
|
||||||
|
{
|
||||||
|
invoke_context.consume_checked($cu_to_consume)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
consumption_result
|
||||||
|
.and_then(|_| {
|
||||||
|
process_instruction_inner(invoke_context)
|
||||||
|
.map(|_| 0)
|
||||||
|
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>)
|
||||||
|
})
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
let consumption_result = if $cu_to_consume > 0
|
);
|
||||||
&& invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&solana_sdk::feature_set::native_programs_consume_cu::id())
|
|
||||||
{
|
|
||||||
invoke_context.consume_checked($cu_to_consume)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
*result = consumption_result
|
|
||||||
.and_then(|_| {
|
|
||||||
process_instruction_inner(invoke_context)
|
|
||||||
.map(|_| 0)
|
|
||||||
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>)
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,11 +471,11 @@ impl<'a> InvokeContext<'a> {
|
||||||
.programs_loaded_for_tx_batch
|
.programs_loaded_for_tx_batch
|
||||||
.find(&builtin_id)
|
.find(&builtin_id)
|
||||||
.ok_or(InstructionError::UnsupportedProgramId)?;
|
.ok_or(InstructionError::UnsupportedProgramId)?;
|
||||||
let process_instruction = match &entry.program {
|
let function = match &entry.program {
|
||||||
LoadedProgramType::Builtin(program) => program
|
LoadedProgramType::Builtin(program) => program
|
||||||
.get_function_registry()
|
.get_function_registry()
|
||||||
.lookup_by_key(ENTRYPOINT_KEY)
|
.lookup_by_key(ENTRYPOINT_KEY)
|
||||||
.map(|(_name, process_instruction)| process_instruction),
|
.map(|(_name, function)| function),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.ok_or(InstructionError::UnsupportedProgramId)?;
|
.ok_or(InstructionError::UnsupportedProgramId)?;
|
||||||
|
@ -484,31 +487,41 @@ impl<'a> InvokeContext<'a> {
|
||||||
let logger = self.get_log_collector();
|
let logger = self.get_log_collector();
|
||||||
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
|
||||||
let pre_remaining_units = self.get_remaining();
|
let pre_remaining_units = self.get_remaining();
|
||||||
|
// In program-runtime v2 we will create this VM instance only once per transaction.
|
||||||
|
// `program_runtime_environment_v2.get_config()` will be used instead of `mock_config`.
|
||||||
|
// For now, only built-ins are invoked from here, so the VM and its Config are irrelevant.
|
||||||
let mock_config = Config::default();
|
let mock_config = Config::default();
|
||||||
let mut mock_memory_mapping =
|
let empty_memory_mapping =
|
||||||
MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V2).unwrap();
|
MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V1).unwrap();
|
||||||
let mut result = ProgramResult::Ok(0);
|
let mut vm = EbpfVm::new(
|
||||||
process_instruction(
|
self.programs_loaded_for_tx_batch
|
||||||
|
.environments
|
||||||
|
.program_runtime_v2
|
||||||
|
.clone(),
|
||||||
|
&SBPFVersion::V1,
|
||||||
// Removes lifetime tracking
|
// Removes lifetime tracking
|
||||||
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
|
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
|
||||||
|
empty_memory_mapping,
|
||||||
0,
|
0,
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&mut mock_memory_mapping,
|
|
||||||
&mut result,
|
|
||||||
);
|
);
|
||||||
let result = match result {
|
vm.invoke_function(function);
|
||||||
|
let result = match vm.program_result {
|
||||||
ProgramResult::Ok(_) => {
|
ProgramResult::Ok(_) => {
|
||||||
stable_log::program_success(&logger, &program_id);
|
stable_log::program_success(&logger, &program_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ProgramResult::Err(err) => {
|
ProgramResult::Err(ref err) => {
|
||||||
stable_log::program_failure(&logger, &program_id, err.as_ref());
|
if let EbpfError::SyscallError(syscall_error) = err {
|
||||||
if let Some(err) = err.downcast_ref::<InstructionError>() {
|
if let Some(instruction_err) = syscall_error.downcast_ref::<InstructionError>()
|
||||||
Err(err.clone())
|
{
|
||||||
|
stable_log::program_failure(&logger, &program_id, instruction_err);
|
||||||
|
Err(instruction_err.clone())
|
||||||
|
} else {
|
||||||
|
stable_log::program_failure(&logger, &program_id, syscall_error);
|
||||||
|
Err(InstructionError::ProgramFailedToComplete)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
stable_log::program_failure(&logger, &program_id, err);
|
||||||
Err(InstructionError::ProgramFailedToComplete)
|
Err(InstructionError::ProgramFailedToComplete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -699,7 +712,7 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut Invo
|
||||||
mut transaction_accounts: Vec<TransactionAccount>,
|
mut transaction_accounts: Vec<TransactionAccount>,
|
||||||
instruction_account_metas: Vec<AccountMeta>,
|
instruction_account_metas: Vec<AccountMeta>,
|
||||||
expected_result: Result<(), InstructionError>,
|
expected_result: Result<(), InstructionError>,
|
||||||
process_instruction: ProcessInstructionWithContext,
|
builtin_function: BuiltinFunctionWithContext,
|
||||||
mut pre_adjustments: F,
|
mut pre_adjustments: F,
|
||||||
mut post_adjustments: G,
|
mut post_adjustments: G,
|
||||||
) -> Vec<AccountSharedData> {
|
) -> Vec<AccountSharedData> {
|
||||||
|
@ -734,7 +747,7 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut Invo
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
*loader_id,
|
*loader_id,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, builtin_function)),
|
||||||
);
|
);
|
||||||
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
||||||
pre_adjustments(&mut invoke_context);
|
pre_adjustments(&mut invoke_context);
|
||||||
|
@ -782,7 +795,7 @@ mod tests {
|
||||||
const MOCK_BUILTIN_COMPUTE_UNIT_COST: u64 = 1;
|
const MOCK_BUILTIN_COMPUTE_UNIT_COST: u64 = 1;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(
|
||||||
process_instruction,
|
MockBuiltin,
|
||||||
MOCK_BUILTIN_COMPUTE_UNIT_COST,
|
MOCK_BUILTIN_COMPUTE_UNIT_COST,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
@ -988,7 +1001,7 @@ mod tests {
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
callee_program_id,
|
callee_program_id,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
|
||||||
);
|
);
|
||||||
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
||||||
|
|
||||||
|
@ -1134,7 +1147,7 @@ mod tests {
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
program_key,
|
program_key,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
|
||||||
);
|
);
|
||||||
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
invoke_context::{InvokeContext, ProcessInstructionWithContext},
|
invoke_context::{BuiltinFunctionWithContext, InvokeContext},
|
||||||
timings::ExecuteDetailsTimings,
|
timings::ExecuteDetailsTimings,
|
||||||
},
|
},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
|
@ -8,9 +8,10 @@ use {
|
||||||
percentage::PercentageInteger,
|
percentage::PercentageInteger,
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
elf::{Executable, FunctionRegistry},
|
elf::Executable,
|
||||||
|
program::{BuiltinProgram, FunctionRegistry},
|
||||||
verifier::RequisiteVerifier,
|
verifier::RequisiteVerifier,
|
||||||
vm::{BuiltinProgram, Config},
|
vm::Config,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
|
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
|
||||||
|
@ -370,11 +371,11 @@ impl LoadedProgram {
|
||||||
pub fn new_builtin(
|
pub fn new_builtin(
|
||||||
deployment_slot: Slot,
|
deployment_slot: Slot,
|
||||||
account_size: usize,
|
account_size: usize,
|
||||||
entrypoint: ProcessInstructionWithContext,
|
builtin_function: BuiltinFunctionWithContext,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut function_registry = FunctionRegistry::default();
|
let mut function_registry = FunctionRegistry::default();
|
||||||
function_registry
|
function_registry
|
||||||
.register_function_hashed(*b"entrypoint", entrypoint)
|
.register_function_hashed(*b"entrypoint", builtin_function)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Self {
|
Self {
|
||||||
deployment_slot,
|
deployment_slot,
|
||||||
|
@ -949,7 +950,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
assert_matches::assert_matches,
|
assert_matches::assert_matches,
|
||||||
percentage::Percentage,
|
percentage::Percentage,
|
||||||
solana_rbpf::vm::BuiltinProgram,
|
solana_rbpf::program::BuiltinProgram,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
|
|
@ -220,7 +220,7 @@ mod tests {
|
||||||
ChangeData { data: u8 },
|
ChangeData { data: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -271,7 +271,7 @@ mod tests {
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
mock_system_program_id,
|
mock_system_program_id,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
|
||||||
);
|
);
|
||||||
let account_keys = (0..transaction_context.get_number_of_accounts())
|
let account_keys = (0..transaction_context.get_number_of_accounts())
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
|
@ -432,7 +432,7 @@ mod tests {
|
||||||
DoWork { lamports: u64, data: u8 },
|
DoWork { lamports: u64, data: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -500,7 +500,7 @@ mod tests {
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
mock_program_id,
|
mock_program_id,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
|
||||||
);
|
);
|
||||||
let account_metas = vec![
|
let account_metas = vec![
|
||||||
AccountMeta::new(
|
AccountMeta::new(
|
||||||
|
@ -645,7 +645,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_precompile() {
|
fn test_precompile() {
|
||||||
let mock_program_id = Pubkey::new_unique();
|
let mock_program_id = Pubkey::new_unique();
|
||||||
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
|
||||||
Err(InstructionError::Custom(0xbabb1e))
|
Err(InstructionError::Custom(0xbabb1e))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -684,7 +684,7 @@ mod tests {
|
||||||
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
|
||||||
programs_loaded_for_tx_batch.replenish(
|
programs_loaded_for_tx_batch.replenish(
|
||||||
mock_program_id,
|
mock_program_id,
|
||||||
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
|
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
|
||||||
);
|
);
|
||||||
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
|
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
|
||||||
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
|
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
|
||||||
|
|
|
@ -101,10 +101,10 @@ pub fn program_success(log_collector: &Option<Rc<RefCell<LogCollector>>>, progra
|
||||||
/// ```notrust
|
/// ```notrust
|
||||||
/// "Program <address> failed: <program error details>"
|
/// "Program <address> failed: <program error details>"
|
||||||
/// ```
|
/// ```
|
||||||
pub fn program_failure(
|
pub fn program_failure<E: std::fmt::Display>(
|
||||||
log_collector: &Option<Rc<RefCell<LogCollector>>>,
|
log_collector: &Option<Rc<RefCell<LogCollector>>>,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
err: &dyn std::error::Error,
|
err: &E,
|
||||||
) {
|
) {
|
||||||
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
|
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ solana-program-runtime = { workspace = true }
|
||||||
solana-runtime = { workspace = true }
|
solana-runtime = { workspace = true }
|
||||||
solana-sdk = { workspace = true }
|
solana-sdk = { workspace = true }
|
||||||
solana-vote-program = { workspace = true }
|
solana-vote-program = { workspace = true }
|
||||||
|
solana_rbpf = { workspace = true }
|
||||||
test-case = { workspace = true }
|
test-case = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -13,7 +13,7 @@ use {
|
||||||
solana_banks_server::banks_server::start_local_server,
|
solana_banks_server::banks_server::start_local_server,
|
||||||
solana_bpf_loader_program::serialization::serialize_parameters,
|
solana_bpf_loader_program::serialization::serialize_parameters,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
compute_budget::ComputeBudget, ic_msg, invoke_context::ProcessInstructionWithContext,
|
compute_budget::ComputeBudget, ic_msg, invoke_context::BuiltinFunctionWithContext,
|
||||||
loaded_programs::LoadedProgram, stable_log, timings::ExecuteTimings,
|
loaded_programs::LoadedProgram, stable_log, timings::ExecuteTimings,
|
||||||
},
|
},
|
||||||
solana_runtime::{
|
solana_runtime::{
|
||||||
|
@ -66,6 +66,10 @@ pub use {
|
||||||
solana_banks_client::{BanksClient, BanksClientError},
|
solana_banks_client::{BanksClient, BanksClientError},
|
||||||
solana_banks_interface::BanksTransactionResultWithMetadata,
|
solana_banks_interface::BanksTransactionResultWithMetadata,
|
||||||
solana_program_runtime::invoke_context::InvokeContext,
|
solana_program_runtime::invoke_context::InvokeContext,
|
||||||
|
solana_rbpf::{
|
||||||
|
error::EbpfError,
|
||||||
|
vm::{get_runtime_environment_key, EbpfVm},
|
||||||
|
},
|
||||||
solana_sdk::transaction_context::IndexOfAccount,
|
solana_sdk::transaction_context::IndexOfAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,10 +98,10 @@ fn get_invoke_context<'a, 'b>() -> &'a mut InvokeContext<'b> {
|
||||||
unsafe { transmute::<usize, &mut InvokeContext>(ptr) }
|
unsafe { transmute::<usize, &mut InvokeContext>(ptr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builtin_process_instruction(
|
pub fn invoke_builtin_function(
|
||||||
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
|
builtin_function: solana_sdk::entrypoint::ProcessInstruction,
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<u64, Box<dyn std::error::Error>> {
|
||||||
set_invoke_context(invoke_context);
|
set_invoke_context(invoke_context);
|
||||||
|
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
@ -130,9 +134,10 @@ pub fn builtin_process_instruction(
|
||||||
unsafe { deserialize(&mut parameter_bytes.as_slice_mut()[0] as *mut u8) };
|
unsafe { deserialize(&mut parameter_bytes.as_slice_mut()[0] as *mut u8) };
|
||||||
|
|
||||||
// Execute the program
|
// Execute the program
|
||||||
process_instruction(program_id, &account_infos, instruction_data).map_err(|err| {
|
builtin_function(program_id, &account_infos, instruction_data).map_err(|err| {
|
||||||
let err: Box<dyn std::error::Error> = Box::new(InstructionError::from(u64::from(err)));
|
let err = InstructionError::from(u64::from(err));
|
||||||
stable_log::program_failure(&log_collector, program_id, err.as_ref());
|
stable_log::program_failure(&log_collector, program_id, &err);
|
||||||
|
let err: Box<dyn std::error::Error> = Box::new(err);
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
stable_log::program_success(&log_collector, program_id);
|
stable_log::program_success(&log_collector, program_id);
|
||||||
|
@ -169,21 +174,24 @@ pub fn builtin_process_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a `solana-program`-style entrypoint into the runtime's entrypoint style, for
|
/// Converts a `solana-program`-style entrypoint into the runtime's entrypoint style, for
|
||||||
/// use with `ProgramTest::add_program`
|
/// use with `ProgramTest::add_program`
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! processor {
|
macro_rules! processor {
|
||||||
($process_instruction:expr) => {
|
($builtin_function:expr) => {
|
||||||
Some(
|
Some(|vm, _arg0, _arg1, _arg2, _arg3, _arg4| {
|
||||||
|invoke_context, _arg0, _arg1, _arg2, _arg3, _arg4, _memory_mapping, result| {
|
let vm = unsafe {
|
||||||
*result = $crate::builtin_process_instruction($process_instruction, invoke_context)
|
&mut *((vm as *mut u64).offset(-($crate::get_runtime_environment_key() as isize))
|
||||||
.map(|_| 0)
|
as *mut $crate::EbpfVm<$crate::InvokeContext>)
|
||||||
|
};
|
||||||
|
vm.program_result =
|
||||||
|
$crate::invoke_builtin_function($builtin_function, vm.context_object_pointer)
|
||||||
|
.map_err(|err| $crate::EbpfError::SyscallError(err))
|
||||||
.into();
|
.into();
|
||||||
},
|
})
|
||||||
)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,10 +514,10 @@ impl ProgramTest {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program_name: &str,
|
program_name: &str,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
process_instruction: Option<ProcessInstructionWithContext>,
|
builtin_function: Option<BuiltinFunctionWithContext>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut me = Self::default();
|
let mut me = Self::default();
|
||||||
me.add_program(program_name, program_id, process_instruction);
|
me.add_program(program_name, program_id, builtin_function);
|
||||||
me
|
me
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,13 +608,13 @@ impl ProgramTest {
|
||||||
/// `program_name` will also be used to locate the SBF shared object in the current or fixtures
|
/// `program_name` will also be used to locate the SBF shared object in the current or fixtures
|
||||||
/// directory.
|
/// directory.
|
||||||
///
|
///
|
||||||
/// If `process_instruction` is provided, the natively built-program may be used instead of the
|
/// If `builtin_function` is provided, the natively built-program may be used instead of the
|
||||||
/// SBF shared object depending on the `BPF_OUT_DIR` environment variable.
|
/// SBF shared object depending on the `BPF_OUT_DIR` environment variable.
|
||||||
pub fn add_program(
|
pub fn add_program(
|
||||||
&mut self,
|
&mut self,
|
||||||
program_name: &str,
|
program_name: &str,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
process_instruction: Option<ProcessInstructionWithContext>,
|
builtin_function: Option<BuiltinFunctionWithContext>,
|
||||||
) {
|
) {
|
||||||
let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| {
|
let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| {
|
||||||
let data = read_file(&program_file);
|
let data = read_file(&program_file);
|
||||||
|
@ -680,7 +688,7 @@ impl ProgramTest {
|
||||||
};
|
};
|
||||||
|
|
||||||
let program_file = find_file(&format!("{program_name}.so"));
|
let program_file = find_file(&format!("{program_name}.so"));
|
||||||
match (self.prefer_bpf, program_file, process_instruction) {
|
match (self.prefer_bpf, program_file, builtin_function) {
|
||||||
// If SBF is preferred (i.e., `test-sbf` is invoked) and a BPF shared object exists,
|
// If SBF is preferred (i.e., `test-sbf` is invoked) and a BPF shared object exists,
|
||||||
// use that as the program data.
|
// use that as the program data.
|
||||||
(true, Some(file), _) => add_bpf(self, file),
|
(true, Some(file), _) => add_bpf(self, file),
|
||||||
|
@ -689,8 +697,8 @@ impl ProgramTest {
|
||||||
// processor function as is.
|
// processor function as is.
|
||||||
//
|
//
|
||||||
// TODO: figure out why tests hang if a processor panics when running native code.
|
// TODO: figure out why tests hang if a processor panics when running native code.
|
||||||
(false, _, Some(process)) => {
|
(false, _, Some(builtin_function)) => {
|
||||||
self.add_builtin_program(program_name, program_id, process)
|
self.add_builtin_program(program_name, program_id, builtin_function)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid: `test-sbf` invocation with no matching SBF shared object.
|
// Invalid: `test-sbf` invocation with no matching SBF shared object.
|
||||||
|
@ -713,13 +721,13 @@ impl ProgramTest {
|
||||||
&mut self,
|
&mut self,
|
||||||
program_name: &str,
|
program_name: &str,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
process_instruction: ProcessInstructionWithContext,
|
builtin_function: BuiltinFunctionWithContext,
|
||||||
) {
|
) {
|
||||||
info!("\"{}\" builtin program", program_name);
|
info!("\"{}\" builtin program", program_name);
|
||||||
self.builtin_programs.push((
|
self.builtin_programs.push((
|
||||||
program_id,
|
program_id,
|
||||||
program_name.to_string(),
|
program_name.to_string(),
|
||||||
LoadedProgram::new_builtin(0, program_name.len(), process_instruction),
|
LoadedProgram::new_builtin(0, program_name.len(), builtin_function),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use {
|
use {
|
||||||
solana_address_lookup_table_program::processor::process_instruction,
|
|
||||||
solana_program_test::*,
|
solana_program_test::*,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::AccountSharedData,
|
account::AccountSharedData,
|
||||||
|
@ -20,7 +19,11 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn setup_test_context() -> ProgramTestContext {
|
pub async fn setup_test_context() -> ProgramTestContext {
|
||||||
let program_test = ProgramTest::new("", id(), Some(process_instruction));
|
let program_test = ProgramTest::new(
|
||||||
|
"",
|
||||||
|
id(),
|
||||||
|
Some(solana_address_lookup_table_program::processor::Entrypoint::vm),
|
||||||
|
);
|
||||||
program_test.start_with_context().await
|
program_test.start_with_context().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
assert_matches::assert_matches,
|
assert_matches::assert_matches,
|
||||||
common::{assert_ix_error, overwrite_slot_hashes_with_slots, setup_test_context},
|
common::{assert_ix_error, overwrite_slot_hashes_with_slots, setup_test_context},
|
||||||
solana_address_lookup_table_program::processor::process_instruction,
|
|
||||||
solana_program_test::*,
|
solana_program_test::*,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
address_lookup_table::{
|
address_lookup_table::{
|
||||||
|
@ -23,7 +22,11 @@ use {
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
pub async fn setup_test_context_without_authority_feature() -> ProgramTestContext {
|
pub async fn setup_test_context_without_authority_feature() -> ProgramTestContext {
|
||||||
let mut program_test = ProgramTest::new("", id(), Some(process_instruction));
|
let mut program_test = ProgramTest::new(
|
||||||
|
"",
|
||||||
|
id(),
|
||||||
|
Some(solana_address_lookup_table_program::processor::Entrypoint::vm),
|
||||||
|
);
|
||||||
program_test.deactivate_feature(
|
program_test.deactivate_feature(
|
||||||
feature_set::relax_authority_signer_check_for_lookup_table_creation::id(),
|
feature_set::relax_authority_signer_check_for_lookup_table_creation::id(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,29 +21,25 @@ use {
|
||||||
|
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
|
||||||
process_instruction,
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
DEFAULT_COMPUTE_UNITS,
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|invoke_context| {
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
match limited_deserialize(instruction_data)? {
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
ProgramInstruction::CreateLookupTable {
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
recent_slot,
|
||||||
match limited_deserialize(instruction_data)? {
|
bump_seed,
|
||||||
ProgramInstruction::CreateLookupTable {
|
} => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed),
|
||||||
recent_slot,
|
ProgramInstruction::FreezeLookupTable => Processor::freeze_lookup_table(invoke_context),
|
||||||
bump_seed,
|
ProgramInstruction::ExtendLookupTable { new_addresses } => {
|
||||||
} => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed),
|
Processor::extend_lookup_table(invoke_context, new_addresses)
|
||||||
ProgramInstruction::FreezeLookupTable => Processor::freeze_lookup_table(invoke_context),
|
|
||||||
ProgramInstruction::ExtendLookupTable { new_addresses } => {
|
|
||||||
Processor::extend_lookup_table(invoke_context, new_addresses)
|
|
||||||
}
|
|
||||||
ProgramInstruction::DeactivateLookupTable => {
|
|
||||||
Processor::deactivate_lookup_table(invoke_context)
|
|
||||||
}
|
|
||||||
ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context),
|
|
||||||
}
|
}
|
||||||
|
ProgramInstruction::DeactivateLookupTable => {
|
||||||
|
Processor::deactivate_lookup_table(invoke_context)
|
||||||
|
}
|
||||||
|
ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context),
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> {
|
fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> {
|
||||||
a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow)
|
a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
solana_bpf_loader_program::process_instruction,
|
|
||||||
solana_program_test::*,
|
solana_program_test::*,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::AccountSharedData,
|
account::AccountSharedData,
|
||||||
|
@ -15,7 +14,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn setup_test_context() -> ProgramTestContext {
|
pub async fn setup_test_context() -> ProgramTestContext {
|
||||||
let program_test = ProgramTest::new("", id(), Some(process_instruction));
|
let program_test = ProgramTest::new("", id(), Some(solana_bpf_loader_program::Entrypoint::vm));
|
||||||
program_test.start_with_context().await
|
program_test.start_with_context().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,14 @@ use {
|
||||||
},
|
},
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
aligned_memory::AlignedMemory,
|
aligned_memory::AlignedMemory,
|
||||||
|
declare_builtin_function,
|
||||||
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
|
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
|
||||||
elf::Executable,
|
elf::Executable,
|
||||||
error::EbpfError,
|
error::{EbpfError, ProgramResult},
|
||||||
memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
|
memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
|
||||||
|
program::BuiltinProgram,
|
||||||
verifier::RequisiteVerifier,
|
verifier::RequisiteVerifier,
|
||||||
vm::{BuiltinProgram, ContextObject, EbpfVm, ProgramResult},
|
vm::{ContextObject, EbpfVm},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::WritableAccount,
|
account::WritableAccount,
|
||||||
|
@ -265,7 +267,7 @@ pub fn create_vm<'a, 'b>(
|
||||||
trace_log: Vec::new(),
|
trace_log: Vec::new(),
|
||||||
})?;
|
})?;
|
||||||
Ok(EbpfVm::new(
|
Ok(EbpfVm::new(
|
||||||
program.get_config(),
|
program.get_loader().clone(),
|
||||||
program.get_sbpf_version(),
|
program.get_sbpf_version(),
|
||||||
invoke_context,
|
invoke_context,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
|
@ -317,7 +319,7 @@ macro_rules! create_vm {
|
||||||
macro_rules! mock_create_vm {
|
macro_rules! mock_create_vm {
|
||||||
($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
|
($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
|
||||||
let loader = std::sync::Arc::new(BuiltinProgram::new_mock());
|
let loader = std::sync::Arc::new(BuiltinProgram::new_mock());
|
||||||
let function_registry = solana_rbpf::elf::FunctionRegistry::default();
|
let function_registry = solana_rbpf::program::FunctionRegistry::default();
|
||||||
let executable = solana_rbpf::elf::Executable::<InvokeContext>::from_text_bytes(
|
let executable = solana_rbpf::elf::Executable::<InvokeContext>::from_text_bytes(
|
||||||
&[0x95, 0, 0, 0, 0, 0, 0, 0],
|
&[0x95, 0, 0, 0, 0, 0, 0, 0],
|
||||||
loader,
|
loader,
|
||||||
|
@ -371,20 +373,22 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(
|
declare_builtin_function!(
|
||||||
invoke_context: &mut InvokeContext,
|
Entrypoint,
|
||||||
_arg0: u64,
|
fn rust(
|
||||||
_arg1: u64,
|
invoke_context: &mut InvokeContext,
|
||||||
_arg2: u64,
|
_arg0: u64,
|
||||||
_arg3: u64,
|
_arg1: u64,
|
||||||
_arg4: u64,
|
_arg2: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_arg3: u64,
|
||||||
result: &mut ProgramResult,
|
_arg4: u64,
|
||||||
) {
|
_memory_mapping: &mut MemoryMapping,
|
||||||
*result = process_instruction_inner(invoke_context).into();
|
) -> Result<u64, Box<dyn std::error::Error>> {
|
||||||
}
|
process_instruction_inner(invoke_context)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
fn process_instruction_inner(
|
pub fn process_instruction_inner(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<u64, Box<dyn std::error::Error>> {
|
) -> Result<u64, Box<dyn std::error::Error>> {
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
|
@ -1607,13 +1611,12 @@ fn execute<'a, 'b: 'a>(
|
||||||
}
|
}
|
||||||
ProgramResult::Err(mut error) => {
|
ProgramResult::Err(mut error) => {
|
||||||
if direct_mapping {
|
if direct_mapping {
|
||||||
if let Some(EbpfError::AccessViolation(
|
if let EbpfError::AccessViolation(
|
||||||
_pc,
|
|
||||||
AccessType::Store,
|
AccessType::Store,
|
||||||
address,
|
address,
|
||||||
_size,
|
_size,
|
||||||
_section_name,
|
_section_name,
|
||||||
)) = error.downcast_ref()
|
) = error
|
||||||
{
|
{
|
||||||
// If direct_mapping is enabled and a program tries to write to a readonly
|
// If direct_mapping is enabled and a program tries to write to a readonly
|
||||||
// region we'll get a memory access violation. Map it to a more specific
|
// region we'll get a memory access violation. Map it to a more specific
|
||||||
|
@ -1621,7 +1624,7 @@ fn execute<'a, 'b: 'a>(
|
||||||
if let Some((instruction_account_index, _)) = account_region_addrs
|
if let Some((instruction_account_index, _)) = account_region_addrs
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, vm_region)| vm_region.contains(address))
|
.find(|(_, vm_region)| vm_region.contains(&address))
|
||||||
{
|
{
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context =
|
let instruction_context =
|
||||||
|
@ -1632,17 +1635,21 @@ fn execute<'a, 'b: 'a>(
|
||||||
instruction_account_index as IndexOfAccount,
|
instruction_account_index as IndexOfAccount,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
error = Box::new(if account.is_executable() {
|
error = EbpfError::SyscallError(Box::new(if account.is_executable() {
|
||||||
InstructionError::ExecutableDataModified
|
InstructionError::ExecutableDataModified
|
||||||
} else if account.is_writable() {
|
} else if account.is_writable() {
|
||||||
InstructionError::ExternalAccountDataModified
|
InstructionError::ExternalAccountDataModified
|
||||||
} else {
|
} else {
|
||||||
InstructionError::ReadonlyDataModified
|
InstructionError::ReadonlyDataModified
|
||||||
})
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error)
|
Err(if let EbpfError::SyscallError(err) = error {
|
||||||
|
err
|
||||||
|
} else {
|
||||||
|
error.into()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
|
@ -1790,7 +1797,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
test_utils::load_all_invoked_programs(invoke_context);
|
test_utils::load_all_invoked_programs(invoke_context);
|
||||||
},
|
},
|
||||||
|
@ -2009,7 +2016,7 @@ mod tests {
|
||||||
vec![(program_id, program_account.clone())],
|
vec![(program_id, program_account.clone())],
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
Err(InstructionError::ProgramFailedToComplete),
|
Err(InstructionError::ProgramFailedToComplete),
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context.mock_set_remaining(0);
|
invoke_context.mock_set_remaining(0);
|
||||||
test_utils::load_all_invoked_programs(invoke_context);
|
test_utils::load_all_invoked_programs(invoke_context);
|
||||||
|
@ -2555,7 +2562,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
crate::{declare_syscall, serialization::account_data_region_memory_state},
|
crate::serialization::account_data_region_memory_state,
|
||||||
scopeguard::defer,
|
scopeguard::defer,
|
||||||
solana_program_runtime::invoke_context::SerializedAccountMetadata,
|
solana_program_runtime::invoke_context::SerializedAccountMetadata,
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
|
@ -455,10 +455,10 @@ trait SyscallInvokeSigned {
|
||||||
) -> Result<Vec<Pubkey>, Error>;
|
) -> Result<Vec<Pubkey>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Cross-program invocation called from Rust
|
/// Cross-program invocation called from Rust
|
||||||
SyscallInvokeSignedRust,
|
SyscallInvokeSignedRust,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
instruction_addr: u64,
|
instruction_addr: u64,
|
||||||
account_infos_addr: u64,
|
account_infos_addr: u64,
|
||||||
|
@ -689,10 +689,10 @@ struct SolSignerSeedsC {
|
||||||
len: u64,
|
len: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Cross-program invocation called from C
|
/// Cross-program invocation called from C
|
||||||
SyscallInvokeSignedC,
|
SyscallInvokeSignedC,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
instruction_addr: u64,
|
instruction_addr: u64,
|
||||||
account_infos_addr: u64,
|
account_infos_addr: u64,
|
||||||
|
@ -1730,7 +1730,7 @@ mod tests {
|
||||||
invoke_context::SerializedAccountMetadata, with_mock_invoke_context,
|
invoke_context::SerializedAccountMetadata, with_mock_invoke_context,
|
||||||
},
|
},
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
ebpf::MM_INPUT_START, elf::SBPFVersion, memory_region::MemoryRegion, vm::Config,
|
ebpf::MM_INPUT_START, memory_region::MemoryRegion, program::SBPFVersion, vm::Config,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{Account, AccountSharedData},
|
account::{Account, AccountSharedData},
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use {super::*, crate::declare_syscall, solana_rbpf::vm::ContextObject};
|
use {super::*, solana_rbpf::vm::ContextObject};
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Log a user's info message
|
/// Log a user's info message
|
||||||
SyscallLog,
|
SyscallLog,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
len: u64,
|
len: u64,
|
||||||
|
@ -36,10 +36,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Log 5 64-bit values
|
/// Log 5 64-bit values
|
||||||
SyscallLogU64,
|
SyscallLogU64,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
arg1: u64,
|
arg1: u64,
|
||||||
arg2: u64,
|
arg2: u64,
|
||||||
|
@ -59,10 +59,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Log current compute consumption
|
/// Log current compute consumption
|
||||||
SyscallLogBpfComputeUnits,
|
SyscallLogBpfComputeUnits,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
_arg1: u64,
|
_arg1: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -83,10 +83,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Log 5 64-bit values
|
/// Log 5 64-bit values
|
||||||
SyscallLogPubkey,
|
SyscallLogPubkey,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
pubkey_addr: u64,
|
pubkey_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -108,10 +108,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Log data handling
|
/// Log data handling
|
||||||
SyscallLogData,
|
SyscallLogData,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
len: u64,
|
len: u64,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
crate::declare_syscall,
|
|
||||||
solana_rbpf::{error::EbpfError, memory_region::MemoryRegion},
|
solana_rbpf::{error::EbpfError, memory_region::MemoryRegion},
|
||||||
std::slice,
|
std::slice,
|
||||||
};
|
};
|
||||||
|
@ -14,10 +13,10 @@ fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Erro
|
||||||
consume_compute_meter(invoke_context, cost)
|
consume_compute_meter(invoke_context, cost)
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// memcpy
|
/// memcpy
|
||||||
SyscallMemcpy,
|
SyscallMemcpy,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
dst_addr: u64,
|
dst_addr: u64,
|
||||||
src_addr: u64,
|
src_addr: u64,
|
||||||
|
@ -37,10 +36,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// memmove
|
/// memmove
|
||||||
SyscallMemmove,
|
SyscallMemmove,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
dst_addr: u64,
|
dst_addr: u64,
|
||||||
src_addr: u64,
|
src_addr: u64,
|
||||||
|
@ -55,10 +54,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// memcmp
|
/// memcmp
|
||||||
SyscallMemcmp,
|
SyscallMemcmp,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
s1_addr: u64,
|
s1_addr: u64,
|
||||||
s2_addr: u64,
|
s2_addr: u64,
|
||||||
|
@ -113,10 +112,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// memset
|
/// memset
|
||||||
SyscallMemset,
|
SyscallMemset,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
dst_addr: u64,
|
dst_addr: u64,
|
||||||
c: u64,
|
c: u64,
|
||||||
|
@ -375,7 +374,6 @@ impl<'a> MemoryChunkIterator<'a> {
|
||||||
len: u64,
|
len: u64,
|
||||||
) -> Result<MemoryChunkIterator<'a>, EbpfError> {
|
) -> Result<MemoryChunkIterator<'a>, EbpfError> {
|
||||||
let vm_addr_end = vm_addr.checked_add(len).ok_or(EbpfError::AccessViolation(
|
let vm_addr_end = vm_addr.checked_add(len).ok_or(EbpfError::AccessViolation(
|
||||||
0,
|
|
||||||
access_type,
|
access_type,
|
||||||
vm_addr,
|
vm_addr,
|
||||||
len,
|
len,
|
||||||
|
@ -394,26 +392,19 @@ impl<'a> MemoryChunkIterator<'a> {
|
||||||
fn region(&mut self, vm_addr: u64) -> Result<&'a MemoryRegion, Error> {
|
fn region(&mut self, vm_addr: u64) -> Result<&'a MemoryRegion, Error> {
|
||||||
match self.memory_mapping.region(self.access_type, vm_addr) {
|
match self.memory_mapping.region(self.access_type, vm_addr) {
|
||||||
Ok(region) => Ok(region),
|
Ok(region) => Ok(region),
|
||||||
Err(error) => match error.downcast_ref() {
|
Err(error) => match error {
|
||||||
Some(EbpfError::AccessViolation(pc, access_type, _vm_addr, _len, name)) => {
|
EbpfError::AccessViolation(access_type, _vm_addr, _len, name) => Err(Box::new(
|
||||||
Err(Box::new(EbpfError::AccessViolation(
|
EbpfError::AccessViolation(access_type, self.initial_vm_addr, self.len, name),
|
||||||
*pc,
|
)),
|
||||||
*access_type,
|
EbpfError::StackAccessViolation(access_type, _vm_addr, _len, frame) => {
|
||||||
self.initial_vm_addr,
|
|
||||||
self.len,
|
|
||||||
name,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
Some(EbpfError::StackAccessViolation(pc, access_type, _vm_addr, _len, frame)) => {
|
|
||||||
Err(Box::new(EbpfError::StackAccessViolation(
|
Err(Box::new(EbpfError::StackAccessViolation(
|
||||||
*pc,
|
access_type,
|
||||||
*access_type,
|
|
||||||
self.initial_vm_addr,
|
self.initial_vm_addr,
|
||||||
self.len,
|
self.len,
|
||||||
*frame,
|
frame,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
_ => Err(error),
|
_ => Err(error.into()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +480,7 @@ mod tests {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
assert_matches::assert_matches,
|
assert_matches::assert_matches,
|
||||||
solana_rbpf::{ebpf::MM_PROGRAM_START, elf::SBPFVersion},
|
solana_rbpf::{ebpf::MM_PROGRAM_START, program::SBPFVersion},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn to_chunk_vec<'a>(
|
fn to_chunk_vec<'a>(
|
||||||
|
@ -547,7 +538,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 42, "unknown") if *addr == MM_PROGRAM_START - 1
|
EbpfError::AccessViolation(AccessType::Load, addr, 42, "unknown") if *addr == MM_PROGRAM_START - 1
|
||||||
);
|
);
|
||||||
|
|
||||||
// check oob at the upper bound. Since the memory mapping isn't empty,
|
// check oob at the upper bound. Since the memory mapping isn't empty,
|
||||||
|
@ -558,7 +549,7 @@ mod tests {
|
||||||
assert!(src_chunk_iter.next().unwrap().is_ok());
|
assert!(src_chunk_iter.next().unwrap().is_ok());
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START
|
EbpfError::AccessViolation(AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START
|
||||||
);
|
);
|
||||||
|
|
||||||
// check oob at the upper bound on the first next_back()
|
// check oob at the upper bound on the first next_back()
|
||||||
|
@ -568,7 +559,7 @@ mod tests {
|
||||||
.rev();
|
.rev();
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START
|
EbpfError::AccessViolation(AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START
|
||||||
);
|
);
|
||||||
|
|
||||||
// check oob at the upper bound on the 2nd next_back()
|
// check oob at the upper bound on the 2nd next_back()
|
||||||
|
@ -579,7 +570,7 @@ mod tests {
|
||||||
assert!(src_chunk_iter.next().unwrap().is_ok());
|
assert!(src_chunk_iter.next().unwrap().is_ok());
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "unknown") if *addr == MM_PROGRAM_START - 1
|
EbpfError::AccessViolation(AccessType::Load, addr, 43, "unknown") if *addr == MM_PROGRAM_START - 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,7 +698,7 @@ mod tests {
|
||||||
false,
|
false,
|
||||||
|_src, _dst, _len| Ok::<_, Error>(0),
|
|_src, _dst, _len| Ok::<_, Error>(0),
|
||||||
).unwrap_err().downcast_ref().unwrap(),
|
).unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 8, "program") if *addr == MM_PROGRAM_START + 8
|
EbpfError::AccessViolation(AccessType::Load, addr, 8, "program") if *addr == MM_PROGRAM_START + 8
|
||||||
);
|
);
|
||||||
|
|
||||||
// src is shorter than dst
|
// src is shorter than dst
|
||||||
|
@ -722,12 +713,12 @@ mod tests {
|
||||||
false,
|
false,
|
||||||
|_src, _dst, _len| Ok::<_, Error>(0),
|
|_src, _dst, _len| Ok::<_, Error>(0),
|
||||||
).unwrap_err().downcast_ref().unwrap(),
|
).unwrap_err().downcast_ref().unwrap(),
|
||||||
EbpfError::AccessViolation(0, AccessType::Load, addr, 3, "program") if *addr == MM_PROGRAM_START + 10
|
EbpfError::AccessViolation(AccessType::Load, addr, 3, "program") if *addr == MM_PROGRAM_START + 10
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "AccessViolation(0, Store, 4294967296, 4")]
|
#[should_panic(expected = "AccessViolation(Store, 4294967296, 4")]
|
||||||
fn test_memmove_non_contiguous_readonly() {
|
fn test_memmove_non_contiguous_readonly() {
|
||||||
let config = Config {
|
let config = Config {
|
||||||
aligned_memory_mapping: false,
|
aligned_memory_mapping: false,
|
||||||
|
@ -817,7 +808,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "AccessViolation(0, Store, 4294967296, 9")]
|
#[should_panic(expected = "AccessViolation(Store, 4294967296, 9")]
|
||||||
fn test_memset_non_contiguous_readonly() {
|
fn test_memset_non_contiguous_readonly() {
|
||||||
let config = Config {
|
let config = Config {
|
||||||
aligned_memory_mapping: false,
|
aligned_memory_mapping: false,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
use {super::*, crate::declare_syscall};
|
use super::*;
|
||||||
|
|
||||||
fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
||||||
sysvar: Result<Arc<T>, InstructionError>,
|
sysvar: Result<Arc<T>, InstructionError>,
|
||||||
|
@ -22,10 +22,10 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
|
||||||
Ok(SUCCESS)
|
Ok(SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a Clock sysvar
|
/// Get a Clock sysvar
|
||||||
SyscallGetClockSysvar,
|
SyscallGetClockSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -44,10 +44,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a EpochSchedule sysvar
|
/// Get a EpochSchedule sysvar
|
||||||
SyscallGetEpochScheduleSysvar,
|
SyscallGetEpochScheduleSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -66,10 +66,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a EpochRewards sysvar
|
/// Get a EpochRewards sysvar
|
||||||
SyscallGetEpochRewardsSysvar,
|
SyscallGetEpochRewardsSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -88,10 +88,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a Fees sysvar
|
/// Get a Fees sysvar
|
||||||
SyscallGetFeesSysvar,
|
SyscallGetFeesSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -113,10 +113,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a Rent sysvar
|
/// Get a Rent sysvar
|
||||||
SyscallGetRentSysvar,
|
SyscallGetRentSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
@ -135,10 +135,10 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_syscall!(
|
declare_builtin_function!(
|
||||||
/// Get a Last Restart Slot sysvar
|
/// Get a Last Restart Slot sysvar
|
||||||
SyscallGetLastRestartSlotSysvar,
|
SyscallGetLastRestartSlotSysvar,
|
||||||
fn inner_call(
|
fn rust(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
var_addr: u64,
|
var_addr: u64,
|
||||||
_arg2: u64,
|
_arg2: u64,
|
||||||
|
|
|
@ -2,11 +2,7 @@ use solana_program_runtime::declare_process_instruction;
|
||||||
|
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |_invoke_context| {
|
||||||
process_instruction,
|
// Do nothing, compute budget instructions handled by the runtime
|
||||||
DEFAULT_COMPUTE_UNITS,
|
Ok(())
|
||||||
|_invoke_context| {
|
});
|
||||||
// Do nothing, compute budget instructions handled by the runtime
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
|
@ -13,131 +13,127 @@ use {
|
||||||
|
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 450;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 450;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
|
||||||
process_instruction,
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
DEFAULT_COMPUTE_UNITS,
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|invoke_context| {
|
let data = instruction_context.get_instruction_data();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
||||||
let data = instruction_context.get_instruction_data();
|
|
||||||
|
|
||||||
let key_list: ConfigKeys = limited_deserialize(data)?;
|
let key_list: ConfigKeys = limited_deserialize(data)?;
|
||||||
let config_account_key = transaction_context.get_key_of_account_at_index(
|
let config_account_key = transaction_context.get_key_of_account_at_index(
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
)?;
|
)?;
|
||||||
let config_account =
|
let config_account =
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
let is_config_account_signer = config_account.is_signer();
|
let is_config_account_signer = config_account.is_signer();
|
||||||
let current_data: ConfigKeys = {
|
let current_data: ConfigKeys = {
|
||||||
if config_account.get_owner() != &crate::id() {
|
if config_account.get_owner() != &crate::id() {
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
}
|
|
||||||
|
|
||||||
deserialize(config_account.get_data()).map_err(|err| {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"Unable to deserialize config account: {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
InstructionError::InvalidAccountData
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
drop(config_account);
|
|
||||||
|
|
||||||
let current_signer_keys: Vec<Pubkey> = current_data
|
|
||||||
.keys
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, is_signer)| *is_signer)
|
|
||||||
.map(|(pubkey, _)| *pubkey)
|
|
||||||
.collect();
|
|
||||||
if current_signer_keys.is_empty() {
|
|
||||||
// Config account keypair must be a signer on account initialization,
|
|
||||||
// or when no signers specified in Config data
|
|
||||||
if !is_config_account_signer {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut counter = 0;
|
deserialize(config_account.get_data()).map_err(|err| {
|
||||||
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
|
|
||||||
counter += 1;
|
|
||||||
if signer != config_account_key {
|
|
||||||
let signer_account = instruction_context
|
|
||||||
.try_borrow_instruction_account(transaction_context, counter as IndexOfAccount)
|
|
||||||
.map_err(|_| {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"account {:?} is not in account list",
|
|
||||||
signer,
|
|
||||||
);
|
|
||||||
InstructionError::MissingRequiredSignature
|
|
||||||
})?;
|
|
||||||
if !signer_account.is_signer() {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"account {:?} signer_key().is_none()",
|
|
||||||
signer
|
|
||||||
);
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
if signer_account.get_key() != signer {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"account[{:?}].signer_key() does not match Config data)",
|
|
||||||
counter + 1
|
|
||||||
);
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
// If Config account is already initialized, update signatures must match Config data
|
|
||||||
if !current_data.keys.is_empty()
|
|
||||||
&& !current_signer_keys.iter().any(|pubkey| pubkey == signer)
|
|
||||||
{
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"account {:?} is not in stored signer list",
|
|
||||||
signer
|
|
||||||
);
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
} else if !is_config_account_signer {
|
|
||||||
ic_msg!(invoke_context, "account[0].signer_key().is_none()");
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::dedupe_config_program_signers::id())
|
|
||||||
{
|
|
||||||
let total_new_keys = key_list.keys.len();
|
|
||||||
let unique_new_keys = key_list.keys.into_iter().collect::<BTreeSet<_>>();
|
|
||||||
if unique_new_keys.len() != total_new_keys {
|
|
||||||
ic_msg!(invoke_context, "new config contains duplicate keys");
|
|
||||||
return Err(InstructionError::InvalidArgument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for Config data signers not present in incoming account update
|
|
||||||
if current_signer_keys.len() > counter {
|
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
"too few signers: {:?}; expected: {:?}",
|
"Unable to deserialize config account: {}",
|
||||||
counter,
|
err
|
||||||
current_signer_keys.len()
|
|
||||||
);
|
);
|
||||||
|
InstructionError::InvalidAccountData
|
||||||
|
})?
|
||||||
|
};
|
||||||
|
drop(config_account);
|
||||||
|
|
||||||
|
let current_signer_keys: Vec<Pubkey> = current_data
|
||||||
|
.keys
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, is_signer)| *is_signer)
|
||||||
|
.map(|(pubkey, _)| *pubkey)
|
||||||
|
.collect();
|
||||||
|
if current_signer_keys.is_empty() {
|
||||||
|
// Config account keypair must be a signer on account initialization,
|
||||||
|
// or when no signers specified in Config data
|
||||||
|
if !is_config_account_signer {
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut config_account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
if config_account.get_data().len() < data.len() {
|
|
||||||
ic_msg!(invoke_context, "instruction data too large");
|
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
|
||||||
}
|
|
||||||
config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
let mut counter = 0;
|
||||||
|
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
|
||||||
|
counter += 1;
|
||||||
|
if signer != config_account_key {
|
||||||
|
let signer_account = instruction_context
|
||||||
|
.try_borrow_instruction_account(transaction_context, counter as IndexOfAccount)
|
||||||
|
.map_err(|_| {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"account {:?} is not in account list",
|
||||||
|
signer,
|
||||||
|
);
|
||||||
|
InstructionError::MissingRequiredSignature
|
||||||
|
})?;
|
||||||
|
if !signer_account.is_signer() {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"account {:?} signer_key().is_none()",
|
||||||
|
signer
|
||||||
|
);
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
if signer_account.get_key() != signer {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"account[{:?}].signer_key() does not match Config data)",
|
||||||
|
counter + 1
|
||||||
|
);
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
// If Config account is already initialized, update signatures must match Config data
|
||||||
|
if !current_data.keys.is_empty()
|
||||||
|
&& !current_signer_keys.iter().any(|pubkey| pubkey == signer)
|
||||||
|
{
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"account {:?} is not in stored signer list",
|
||||||
|
signer
|
||||||
|
);
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
} else if !is_config_account_signer {
|
||||||
|
ic_msg!(invoke_context, "account[0].signer_key().is_none()");
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::dedupe_config_program_signers::id())
|
||||||
|
{
|
||||||
|
let total_new_keys = key_list.keys.len();
|
||||||
|
let unique_new_keys = key_list.keys.into_iter().collect::<BTreeSet<_>>();
|
||||||
|
if unique_new_keys.len() != total_new_keys {
|
||||||
|
ic_msg!(invoke_context, "new config contains duplicate keys");
|
||||||
|
return Err(InstructionError::InvalidArgument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Config data signers not present in incoming account update
|
||||||
|
if current_signer_keys.len() > counter {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"too few signers: {:?}; expected: {:?}",
|
||||||
|
counter,
|
||||||
|
current_signer_keys.len()
|
||||||
|
);
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut config_account =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
if config_account.get_data().len() < data.len() {
|
||||||
|
ic_msg!(invoke_context, "instruction data too large");
|
||||||
|
return Err(InstructionError::InvalidInstructionData);
|
||||||
|
}
|
||||||
|
config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -169,7 +165,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,10 +12,12 @@ use {
|
||||||
},
|
},
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
aligned_memory::AlignedMemory,
|
aligned_memory::AlignedMemory,
|
||||||
ebpf,
|
declare_builtin_function, ebpf,
|
||||||
elf::{Executable, FunctionRegistry},
|
elf::Executable,
|
||||||
|
error::ProgramResult,
|
||||||
memory_region::{MemoryMapping, MemoryRegion},
|
memory_region::{MemoryMapping, MemoryRegion},
|
||||||
vm::{BuiltinProgram, Config, ContextObject, EbpfVm, ProgramResult},
|
program::{BuiltinProgram, FunctionRegistry},
|
||||||
|
vm::{Config, ContextObject, EbpfVm},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
|
@ -81,7 +83,6 @@ pub fn create_program_runtime_environment_v2<'a>(
|
||||||
reject_broken_elfs: true,
|
reject_broken_elfs: true,
|
||||||
noop_instruction_rate: 256,
|
noop_instruction_rate: 256,
|
||||||
sanitize_user_provided_values: true,
|
sanitize_user_provided_values: true,
|
||||||
encrypt_runtime_environment: true,
|
|
||||||
external_internal_function_hash_collision: true,
|
external_internal_function_hash_collision: true,
|
||||||
reject_callx_r10: true,
|
reject_callx_r10: true,
|
||||||
enable_sbpf_v1: false,
|
enable_sbpf_v1: false,
|
||||||
|
@ -131,7 +132,7 @@ pub fn create_vm<'a, 'b>(
|
||||||
Box::new(InstructionError::ProgramEnvironmentSetupFailure)
|
Box::new(InstructionError::ProgramEnvironmentSetupFailure)
|
||||||
})?;
|
})?;
|
||||||
Ok(EbpfVm::new(
|
Ok(EbpfVm::new(
|
||||||
config,
|
program.get_loader().clone(),
|
||||||
sbpf_version,
|
sbpf_version,
|
||||||
invoke_context,
|
invoke_context,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
|
@ -182,9 +183,9 @@ fn execute<'a, 'b: 'a>(
|
||||||
match result {
|
match result {
|
||||||
ProgramResult::Ok(status) if status != SUCCESS => {
|
ProgramResult::Ok(status) if status != SUCCESS => {
|
||||||
let error: InstructionError = status.into();
|
let error: InstructionError = status.into();
|
||||||
Err(Box::new(error) as Box<dyn std::error::Error>)
|
Err(error.into())
|
||||||
}
|
}
|
||||||
ProgramResult::Err(error) => Err(error),
|
ProgramResult::Err(error) => Err(error.into()),
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,18 +528,20 @@ pub fn process_instruction_transfer_authority(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_instruction(
|
declare_builtin_function!(
|
||||||
invoke_context: &mut InvokeContext,
|
Entrypoint,
|
||||||
_arg0: u64,
|
fn rust(
|
||||||
_arg1: u64,
|
invoke_context: &mut InvokeContext,
|
||||||
_arg2: u64,
|
_arg0: u64,
|
||||||
_arg3: u64,
|
_arg1: u64,
|
||||||
_arg4: u64,
|
_arg2: u64,
|
||||||
_memory_mapping: &mut MemoryMapping,
|
_arg3: u64,
|
||||||
result: &mut ProgramResult,
|
_arg4: u64,
|
||||||
) {
|
_memory_mapping: &mut MemoryMapping,
|
||||||
*result = process_instruction_inner(invoke_context).into();
|
) -> Result<u64, Box<dyn std::error::Error>> {
|
||||||
}
|
process_instruction_inner(invoke_context)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
pub fn process_instruction_inner(
|
pub fn process_instruction_inner(
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
|
@ -700,7 +703,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context
|
invoke_context
|
||||||
.programs_modified_by_tx
|
.programs_modified_by_tx
|
||||||
|
|
|
@ -5341,6 +5341,7 @@ dependencies = [
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
|
"solana_rbpf",
|
||||||
"test-case",
|
"test-case",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -6514,9 +6515,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.7.2"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196"
|
checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.5.0",
|
"byteorder 1.5.0",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -48,7 +48,7 @@ solana-sdk = { path = "../../sdk", version = "=1.18.0" }
|
||||||
solana-transaction-status = { path = "../../transaction-status", version = "=1.18.0" }
|
solana-transaction-status = { path = "../../transaction-status", version = "=1.18.0" }
|
||||||
solana-validator = { path = "../../validator", version = "=1.18.0" }
|
solana-validator = { path = "../../validator", version = "=1.18.0" }
|
||||||
solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.18.0" }
|
solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.18.0" }
|
||||||
solana_rbpf = "=0.7.2"
|
solana_rbpf = "=0.8.0"
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -1449,7 +1449,7 @@ fn assert_instruction_count() {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
Ok(()),
|
Ok(()),
|
||||||
solana_bpf_loader_program::process_instruction,
|
solana_bpf_loader_program::Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
*prev_compute_meter.borrow_mut() = invoke_context.get_remaining();
|
*prev_compute_meter.borrow_mut() = invoke_context.get_remaining();
|
||||||
solana_bpf_loader_program::test_utils::load_all_invoked_programs(invoke_context);
|
solana_bpf_loader_program::test_utils::load_all_invoked_programs(invoke_context);
|
||||||
|
@ -4397,7 +4397,7 @@ fn test_cpi_change_account_data_memory_allocation() {
|
||||||
let feature_set = FeatureSet::all_enabled();
|
let feature_set = FeatureSet::all_enabled();
|
||||||
bank.feature_set = Arc::new(feature_set);
|
bank.feature_set = Arc::new(feature_set);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 42, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 42, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -4428,7 +4428,7 @@ fn test_cpi_change_account_data_memory_allocation() {
|
||||||
bank.add_builtin(
|
bank.add_builtin(
|
||||||
builtin_program_id,
|
builtin_program_id,
|
||||||
"test_cpi_change_account_data_memory_allocation_builtin".to_string(),
|
"test_cpi_change_account_data_memory_allocation_builtin".to_string(),
|
||||||
LoadedProgram::new_builtin(0, 42, process_instruction),
|
LoadedProgram::new_builtin(0, 42, MockBuiltin::vm),
|
||||||
);
|
);
|
||||||
|
|
||||||
let bank = Arc::new(bank);
|
let bank = Arc::new(bank);
|
||||||
|
|
|
@ -54,411 +54,391 @@ fn get_optional_pubkey<'a>(
|
||||||
|
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
|
||||||
process_instruction,
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
DEFAULT_COMPUTE_UNITS,
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|invoke_context| {
|
let data = instruction_context.get_instruction_data();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
||||||
let data = instruction_context.get_instruction_data();
|
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
let get_stake_account = || {
|
let get_stake_account = || {
|
||||||
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
|
}
|
||||||
|
Ok(me)
|
||||||
|
};
|
||||||
|
|
||||||
|
let signers = instruction_context.get_signers(transaction_context)?;
|
||||||
|
match limited_deserialize(data) {
|
||||||
|
Ok(StakeInstruction::Initialize(authorized, lockup)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
||||||
|
initialize(&mut me, &authorized, &lockup, &rent)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
let require_custodian_for_locked_stake_authorize = invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
|
||||||
|
|
||||||
|
if require_custodian_for_locked_stake_authorize {
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
|
let custodian_pubkey =
|
||||||
|
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
|
||||||
|
|
||||||
|
authorize(
|
||||||
|
&mut me,
|
||||||
|
&signers,
|
||||||
|
&authorized_pubkey,
|
||||||
|
stake_authorize,
|
||||||
|
require_custodian_for_locked_stake_authorize,
|
||||||
|
&clock,
|
||||||
|
custodian_pubkey,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
authorize(
|
||||||
|
&mut me,
|
||||||
|
&signers,
|
||||||
|
&authorized_pubkey,
|
||||||
|
stake_authorize,
|
||||||
|
require_custodian_for_locked_stake_authorize,
|
||||||
|
&Clock::default(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Ok(me)
|
}
|
||||||
};
|
Ok(StakeInstruction::AuthorizeWithSeed(args)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let require_custodian_for_locked_stake_authorize = invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
|
||||||
|
if require_custodian_for_locked_stake_authorize {
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
let custodian_pubkey =
|
||||||
|
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
|
||||||
|
|
||||||
|
authorize_with_seed(
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
&mut me,
|
||||||
|
1,
|
||||||
|
&args.authority_seed,
|
||||||
|
&args.authority_owner,
|
||||||
|
&args.new_authorized_pubkey,
|
||||||
|
args.stake_authorize,
|
||||||
|
require_custodian_for_locked_stake_authorize,
|
||||||
|
&clock,
|
||||||
|
custodian_pubkey,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
authorize_with_seed(
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
&mut me,
|
||||||
|
1,
|
||||||
|
&args.authority_seed,
|
||||||
|
&args.authority_owner,
|
||||||
|
&args.new_authorized_pubkey,
|
||||||
|
args.stake_authorize,
|
||||||
|
require_custodian_for_locked_stake_authorize,
|
||||||
|
&Clock::default(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::DelegateStake) => {
|
||||||
|
let me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
let stake_history = get_sysvar_with_account_check::stake_history(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
3,
|
||||||
|
)?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(5)?;
|
||||||
|
drop(me);
|
||||||
|
if !invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::reduce_stake_warmup_cooldown::id())
|
||||||
|
{
|
||||||
|
// Post feature activation, remove both the feature gate code and the config completely in the interface
|
||||||
|
let config_account =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 4)?;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
if !config::check_id(config_account.get_key()) {
|
||||||
|
return Err(InstructionError::InvalidArgument);
|
||||||
|
}
|
||||||
|
config::from(&config_account).ok_or(InstructionError::InvalidArgument)?;
|
||||||
|
}
|
||||||
|
delegate(
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
&clock,
|
||||||
|
&stake_history,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Split(lamports)) => {
|
||||||
|
let me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
drop(me);
|
||||||
|
split(
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
0,
|
||||||
|
lamports,
|
||||||
|
1,
|
||||||
|
&signers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Merge) => {
|
||||||
|
let me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
let stake_history = get_sysvar_with_account_check::stake_history(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
3,
|
||||||
|
)?;
|
||||||
|
drop(me);
|
||||||
|
merge(
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
&clock,
|
||||||
|
&stake_history,
|
||||||
|
&signers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Withdraw(lamports)) => {
|
||||||
|
let me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
let stake_history = get_sysvar_with_account_check::stake_history(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
3,
|
||||||
|
)?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(5)?;
|
||||||
|
drop(me);
|
||||||
|
withdraw(
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
0,
|
||||||
|
lamports,
|
||||||
|
1,
|
||||||
|
&clock,
|
||||||
|
&stake_history,
|
||||||
|
4,
|
||||||
|
if instruction_context.get_number_of_instruction_accounts() >= 6 {
|
||||||
|
Some(5)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
new_warmup_cooldown_rate_epoch(invoke_context),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Deactivate) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||||
|
deactivate(invoke_context, &mut me, &clock, &signers)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::SetLockup(lockup)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
|
set_lockup(&mut me, &lockup, &signers, &clock)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::InitializeChecked) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
|
let staker_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
|
||||||
|
)?;
|
||||||
|
let withdrawer_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
||||||
|
)?;
|
||||||
|
if !instruction_context.is_instruction_account_signer(3)? {
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
let authorized = Authorized {
|
||||||
|
staker: *staker_pubkey,
|
||||||
|
withdrawer: *withdrawer_pubkey,
|
||||||
|
};
|
||||||
|
|
||||||
let signers = instruction_context.get_signers(transaction_context)?;
|
|
||||||
match limited_deserialize(data) {
|
|
||||||
Ok(StakeInstruction::Initialize(authorized, lockup)) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
let rent =
|
let rent =
|
||||||
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
||||||
initialize(&mut me, &authorized, &lockup, &rent)
|
initialize(&mut me, &authorized, &Lockup::default(), &rent)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
}
|
}
|
||||||
Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => {
|
}
|
||||||
let mut me = get_stake_account()?;
|
Ok(StakeInstruction::AuthorizeChecked(stake_authorize)) => {
|
||||||
let require_custodian_for_locked_stake_authorize = invoke_context
|
let mut me = get_stake_account()?;
|
||||||
.feature_set
|
if invoke_context
|
||||||
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
|
.feature_set
|
||||||
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
if require_custodian_for_locked_stake_authorize {
|
{
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
let clock =
|
||||||
invoke_context,
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||||
instruction_context,
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
1,
|
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
)?;
|
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
)?;
|
||||||
let custodian_pubkey =
|
if !instruction_context.is_instruction_account_signer(3)? {
|
||||||
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
|
||||||
authorize(
|
|
||||||
&mut me,
|
|
||||||
&signers,
|
|
||||||
&authorized_pubkey,
|
|
||||||
stake_authorize,
|
|
||||||
require_custodian_for_locked_stake_authorize,
|
|
||||||
&clock,
|
|
||||||
custodian_pubkey,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
authorize(
|
|
||||||
&mut me,
|
|
||||||
&signers,
|
|
||||||
&authorized_pubkey,
|
|
||||||
stake_authorize,
|
|
||||||
require_custodian_for_locked_stake_authorize,
|
|
||||||
&Clock::default(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
let custodian_pubkey =
|
||||||
Ok(StakeInstruction::AuthorizeWithSeed(args)) => {
|
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let require_custodian_for_locked_stake_authorize = invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::require_custodian_for_locked_stake_authorize::id());
|
|
||||||
if require_custodian_for_locked_stake_authorize {
|
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
2,
|
|
||||||
)?;
|
|
||||||
let custodian_pubkey =
|
|
||||||
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
|
|
||||||
|
|
||||||
authorize_with_seed(
|
authorize(
|
||||||
transaction_context,
|
&mut me,
|
||||||
instruction_context,
|
&signers,
|
||||||
&mut me,
|
authorized_pubkey,
|
||||||
1,
|
stake_authorize,
|
||||||
&args.authority_seed,
|
true,
|
||||||
&args.authority_owner,
|
&clock,
|
||||||
&args.new_authorized_pubkey,
|
custodian_pubkey,
|
||||||
args.stake_authorize,
|
)
|
||||||
require_custodian_for_locked_stake_authorize,
|
} else {
|
||||||
&clock,
|
Err(InstructionError::InvalidInstructionData)
|
||||||
custodian_pubkey,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
authorize_with_seed(
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
&mut me,
|
|
||||||
1,
|
|
||||||
&args.authority_seed,
|
|
||||||
&args.authority_owner,
|
|
||||||
&args.new_authorized_pubkey,
|
|
||||||
args.stake_authorize,
|
|
||||||
require_custodian_for_locked_stake_authorize,
|
|
||||||
&Clock::default(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(StakeInstruction::DelegateStake) => {
|
}
|
||||||
let me = get_stake_account()?;
|
Ok(StakeInstruction::AuthorizeCheckedWithSeed(args)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let clock =
|
let clock =
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
let stake_history = get_sysvar_with_account_check::stake_history(
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
invoke_context,
|
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
instruction_context,
|
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
||||||
3,
|
|
||||||
)?;
|
)?;
|
||||||
instruction_context.check_number_of_instruction_accounts(5)?;
|
if !instruction_context.is_instruction_account_signer(3)? {
|
||||||
drop(me);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
let custodian_pubkey =
|
||||||
|
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
|
||||||
|
|
||||||
|
authorize_with_seed(
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
&mut me,
|
||||||
|
1,
|
||||||
|
&args.authority_seed,
|
||||||
|
&args.authority_owner,
|
||||||
|
authorized_pubkey,
|
||||||
|
args.stake_authorize,
|
||||||
|
true,
|
||||||
|
&clock,
|
||||||
|
custodian_pubkey,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::SetLockupChecked(lockup_checked)) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let custodian_pubkey =
|
||||||
|
get_optional_pubkey(transaction_context, instruction_context, 2, true)?;
|
||||||
|
|
||||||
|
let lockup = LockupArgs {
|
||||||
|
unix_timestamp: lockup_checked.unix_timestamp,
|
||||||
|
epoch: lockup_checked.epoch,
|
||||||
|
custodian: custodian_pubkey.cloned(),
|
||||||
|
};
|
||||||
|
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
|
set_lockup(&mut me, &lockup, &signers, &clock)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::GetMinimumDelegation) => {
|
||||||
|
let feature_set = invoke_context.feature_set.as_ref();
|
||||||
|
let minimum_delegation = crate::get_minimum_delegation(feature_set);
|
||||||
|
let minimum_delegation = Vec::from(minimum_delegation.to_le_bytes());
|
||||||
|
invoke_context
|
||||||
|
.transaction_context
|
||||||
|
.set_return_data(id(), minimum_delegation)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::DeactivateDelinquent) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
|
|
||||||
|
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
|
deactivate_delinquent(
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
&mut me,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
clock.epoch,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(StakeInstruction::Redelegate) => {
|
||||||
|
let mut me = get_stake_account()?;
|
||||||
|
if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::stake_redelegate_instruction::id())
|
||||||
|
{
|
||||||
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
if !invoke_context
|
if !invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&feature_set::reduce_stake_warmup_cooldown::id())
|
.is_active(&feature_set::reduce_stake_warmup_cooldown::id())
|
||||||
{
|
{
|
||||||
// Post feature activation, remove both the feature gate code and the config completely in the interface
|
// Post feature activation, remove both the feature gate code and the config completely in the interface
|
||||||
let config_account = instruction_context
|
let config_account = instruction_context
|
||||||
.try_borrow_instruction_account(transaction_context, 4)?;
|
.try_borrow_instruction_account(transaction_context, 3)?;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
if !config::check_id(config_account.get_key()) {
|
if !config::check_id(config_account.get_key()) {
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
config::from(&config_account).ok_or(InstructionError::InvalidArgument)?;
|
config::from(&config_account).ok_or(InstructionError::InvalidArgument)?;
|
||||||
}
|
}
|
||||||
delegate(
|
redelegate(
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
&clock,
|
|
||||||
&stake_history,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::Split(lamports)) => {
|
|
||||||
let me = get_stake_account()?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
drop(me);
|
|
||||||
split(
|
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
0,
|
|
||||||
lamports,
|
|
||||||
1,
|
|
||||||
&signers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::Merge) => {
|
|
||||||
let me = get_stake_account()?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let clock =
|
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
|
||||||
let stake_history = get_sysvar_with_account_check::stake_history(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
3,
|
|
||||||
)?;
|
|
||||||
drop(me);
|
|
||||||
merge(
|
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
&clock,
|
|
||||||
&stake_history,
|
|
||||||
&signers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::Withdraw(lamports)) => {
|
|
||||||
let me = get_stake_account()?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let clock =
|
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
|
||||||
let stake_history = get_sysvar_with_account_check::stake_history(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
3,
|
|
||||||
)?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(5)?;
|
|
||||||
drop(me);
|
|
||||||
withdraw(
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
0,
|
|
||||||
lamports,
|
|
||||||
1,
|
|
||||||
&clock,
|
|
||||||
&stake_history,
|
|
||||||
4,
|
|
||||||
if instruction_context.get_number_of_instruction_accounts() >= 6 {
|
|
||||||
Some(5)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
new_warmup_cooldown_rate_epoch(invoke_context),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::Deactivate) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
let clock =
|
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
|
||||||
deactivate(invoke_context, &mut me, &clock, &signers)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::SetLockup(lockup)) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
|
||||||
set_lockup(&mut me, &lockup, &signers, &clock)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::InitializeChecked) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
|
||||||
{
|
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
|
||||||
let staker_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
|
|
||||||
)?;
|
|
||||||
let withdrawer_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
|
||||||
)?;
|
|
||||||
if !instruction_context.is_instruction_account_signer(3)? {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
let authorized = Authorized {
|
|
||||||
staker: *staker_pubkey,
|
|
||||||
withdrawer: *withdrawer_pubkey,
|
|
||||||
};
|
|
||||||
|
|
||||||
let rent = get_sysvar_with_account_check::rent(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
initialize(&mut me, &authorized, &Lockup::default(), &rent)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::AuthorizeChecked(stake_authorize)) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
|
||||||
{
|
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
|
||||||
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
|
||||||
)?;
|
|
||||||
if !instruction_context.is_instruction_account_signer(3)? {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
let custodian_pubkey =
|
|
||||||
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
|
|
||||||
|
|
||||||
authorize(
|
|
||||||
&mut me,
|
|
||||||
&signers,
|
|
||||||
authorized_pubkey,
|
|
||||||
stake_authorize,
|
|
||||||
true,
|
|
||||||
&clock,
|
|
||||||
custodian_pubkey,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::AuthorizeCheckedWithSeed(args)) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
|
||||||
{
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
2,
|
|
||||||
)?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
|
||||||
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
|
||||||
)?;
|
|
||||||
if !instruction_context.is_instruction_account_signer(3)? {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
let custodian_pubkey =
|
|
||||||
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
|
|
||||||
|
|
||||||
authorize_with_seed(
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
&mut me,
|
|
||||||
1,
|
|
||||||
&args.authority_seed,
|
|
||||||
&args.authority_owner,
|
|
||||||
authorized_pubkey,
|
|
||||||
args.stake_authorize,
|
|
||||||
true,
|
|
||||||
&clock,
|
|
||||||
custodian_pubkey,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::SetLockupChecked(lockup_checked)) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
|
||||||
{
|
|
||||||
let custodian_pubkey =
|
|
||||||
get_optional_pubkey(transaction_context, instruction_context, 2, true)?;
|
|
||||||
|
|
||||||
let lockup = LockupArgs {
|
|
||||||
unix_timestamp: lockup_checked.unix_timestamp,
|
|
||||||
epoch: lockup_checked.epoch,
|
|
||||||
custodian: custodian_pubkey.cloned(),
|
|
||||||
};
|
|
||||||
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
|
||||||
set_lockup(&mut me, &lockup, &signers, &clock)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::GetMinimumDelegation) => {
|
|
||||||
let feature_set = invoke_context.feature_set.as_ref();
|
|
||||||
let minimum_delegation = crate::get_minimum_delegation(feature_set);
|
|
||||||
let minimum_delegation = Vec::from(minimum_delegation.to_le_bytes());
|
|
||||||
invoke_context
|
|
||||||
.transaction_context
|
|
||||||
.set_return_data(id(), minimum_delegation)
|
|
||||||
}
|
|
||||||
Ok(StakeInstruction::DeactivateDelinquent) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
|
||||||
|
|
||||||
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
|
||||||
deactivate_delinquent(
|
|
||||||
invoke_context,
|
invoke_context,
|
||||||
transaction_context,
|
transaction_context,
|
||||||
instruction_context,
|
instruction_context,
|
||||||
&mut me,
|
&mut me,
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
clock.epoch,
|
&signers,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
}
|
}
|
||||||
Ok(StakeInstruction::Redelegate) => {
|
|
||||||
let mut me = get_stake_account()?;
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::stake_redelegate_instruction::id())
|
|
||||||
{
|
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
|
||||||
if !invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::reduce_stake_warmup_cooldown::id())
|
|
||||||
{
|
|
||||||
// Post feature activation, remove both the feature gate code and the config completely in the interface
|
|
||||||
let config_account = instruction_context
|
|
||||||
.try_borrow_instruction_account(transaction_context, 3)?;
|
|
||||||
#[allow(deprecated)]
|
|
||||||
if !config::check_id(config_account.get_key()) {
|
|
||||||
return Err(InstructionError::InvalidArgument);
|
|
||||||
}
|
|
||||||
config::from(&config_account).ok_or(InstructionError::InvalidArgument)?;
|
|
||||||
}
|
|
||||||
redelegate(
|
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
&mut me,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
&signers,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -572,7 +552,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context.feature_set = Arc::clone(&feature_set);
|
invoke_context.feature_set = Arc::clone(&feature_set);
|
||||||
},
|
},
|
||||||
|
@ -7046,7 +7026,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
Ok(()),
|
Ok(()),
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context.feature_set = Arc::clone(&feature_set);
|
invoke_context.feature_set = Arc::clone(&feature_set);
|
||||||
},
|
},
|
||||||
|
|
|
@ -314,252 +314,246 @@ fn transfer_with_seed(
|
||||||
|
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
|
||||||
process_instruction,
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
DEFAULT_COMPUTE_UNITS,
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|invoke_context| {
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let instruction = limited_deserialize(instruction_data)?;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
|
||||||
let instruction = limited_deserialize(instruction_data)?;
|
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", instruction);
|
trace!("process_instruction: {:?}", instruction);
|
||||||
|
|
||||||
let signers = instruction_context.get_signers(transaction_context)?;
|
let signers = instruction_context.get_signers(transaction_context)?;
|
||||||
match instruction {
|
match instruction {
|
||||||
SystemInstruction::CreateAccount {
|
SystemInstruction::CreateAccount {
|
||||||
|
lamports,
|
||||||
|
space,
|
||||||
|
owner,
|
||||||
|
} => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let to_address = Address::create(
|
||||||
|
transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
||||||
|
)?,
|
||||||
|
None,
|
||||||
|
invoke_context,
|
||||||
|
)?;
|
||||||
|
create_account(
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
&to_address,
|
||||||
lamports,
|
lamports,
|
||||||
space,
|
space,
|
||||||
owner,
|
&owner,
|
||||||
} => {
|
&signers,
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
invoke_context,
|
||||||
let to_address = Address::create(
|
transaction_context,
|
||||||
transaction_context.get_key_of_account_at_index(
|
instruction_context,
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
)
|
||||||
)?,
|
}
|
||||||
None,
|
SystemInstruction::CreateAccountWithSeed {
|
||||||
invoke_context,
|
base,
|
||||||
)?;
|
seed,
|
||||||
create_account(
|
lamports,
|
||||||
0,
|
space,
|
||||||
1,
|
owner,
|
||||||
&to_address,
|
} => {
|
||||||
lamports,
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
space,
|
let to_address = Address::create(
|
||||||
&owner,
|
transaction_context.get_key_of_account_at_index(
|
||||||
&signers,
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
||||||
invoke_context,
|
)?,
|
||||||
transaction_context,
|
Some((&base, &seed, &owner)),
|
||||||
instruction_context,
|
invoke_context,
|
||||||
)
|
)?;
|
||||||
}
|
create_account(
|
||||||
SystemInstruction::CreateAccountWithSeed {
|
0,
|
||||||
base,
|
1,
|
||||||
seed,
|
&to_address,
|
||||||
lamports,
|
lamports,
|
||||||
space,
|
space,
|
||||||
owner,
|
&owner,
|
||||||
} => {
|
&signers,
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
invoke_context,
|
||||||
let to_address = Address::create(
|
transaction_context,
|
||||||
transaction_context.get_key_of_account_at_index(
|
instruction_context,
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
)
|
||||||
)?,
|
}
|
||||||
Some((&base, &seed, &owner)),
|
SystemInstruction::Assign { owner } => {
|
||||||
invoke_context,
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
)?;
|
let mut account =
|
||||||
create_account(
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
0,
|
let address = Address::create(
|
||||||
1,
|
transaction_context.get_key_of_account_at_index(
|
||||||
&to_address,
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
lamports,
|
)?,
|
||||||
space,
|
None,
|
||||||
&owner,
|
invoke_context,
|
||||||
&signers,
|
)?;
|
||||||
invoke_context,
|
assign(&mut account, &address, &owner, &signers, invoke_context)
|
||||||
transaction_context,
|
}
|
||||||
instruction_context,
|
SystemInstruction::Transfer { lamports } => {
|
||||||
)
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
}
|
transfer(
|
||||||
SystemInstruction::Assign { owner } => {
|
0,
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
1,
|
||||||
let mut account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
let address = Address::create(
|
|
||||||
transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
|
||||||
)?,
|
|
||||||
None,
|
|
||||||
invoke_context,
|
|
||||||
)?;
|
|
||||||
assign(&mut account, &address, &owner, &signers, invoke_context)
|
|
||||||
}
|
|
||||||
SystemInstruction::Transfer { lamports } => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
transfer(
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
lamports,
|
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SystemInstruction::TransferWithSeed {
|
|
||||||
lamports,
|
lamports,
|
||||||
from_seed,
|
invoke_context,
|
||||||
from_owner,
|
transaction_context,
|
||||||
} => {
|
instruction_context,
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
)
|
||||||
transfer_with_seed(
|
}
|
||||||
0,
|
SystemInstruction::TransferWithSeed {
|
||||||
1,
|
lamports,
|
||||||
&from_seed,
|
from_seed,
|
||||||
&from_owner,
|
from_owner,
|
||||||
2,
|
} => {
|
||||||
lamports,
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
|
transfer_with_seed(
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
&from_seed,
|
||||||
|
&from_owner,
|
||||||
|
2,
|
||||||
|
lamports,
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SystemInstruction::AdvanceNonceAccount => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
|
let mut me =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
1,
|
||||||
|
)?;
|
||||||
|
if recent_blockhashes.is_empty() {
|
||||||
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
transaction_context,
|
"Advance nonce account: recent blockhash list is empty",
|
||||||
instruction_context,
|
);
|
||||||
)
|
return Err(SystemError::NonceNoRecentBlockhashes.into());
|
||||||
}
|
}
|
||||||
SystemInstruction::AdvanceNonceAccount => {
|
advance_nonce_account(&mut me, &signers, invoke_context)
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
}
|
||||||
let mut me =
|
SystemInstruction::WithdrawNonceAccount(lamports) => {
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
|
||||||
|
withdraw_nonce_account(
|
||||||
|
0,
|
||||||
|
lamports,
|
||||||
|
1,
|
||||||
|
&rent,
|
||||||
|
&signers,
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
instruction_context,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SystemInstruction::InitializeNonceAccount(authorized) => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
|
let mut me =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
1,
|
||||||
|
)?;
|
||||||
|
if recent_blockhashes.is_empty() {
|
||||||
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
instruction_context,
|
"Initialize nonce account: recent blockhash list is empty",
|
||||||
1,
|
);
|
||||||
)?;
|
return Err(SystemError::NonceNoRecentBlockhashes.into());
|
||||||
if recent_blockhashes.is_empty() {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"Advance nonce account: recent blockhash list is empty",
|
|
||||||
);
|
|
||||||
return Err(SystemError::NonceNoRecentBlockhashes.into());
|
|
||||||
}
|
|
||||||
advance_nonce_account(&mut me, &signers, invoke_context)
|
|
||||||
}
|
}
|
||||||
SystemInstruction::WithdrawNonceAccount(lamports) => {
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
|
||||||
#[allow(deprecated)]
|
}
|
||||||
let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
|
||||||
invoke_context,
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
instruction_context,
|
let mut me =
|
||||||
2,
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
)?;
|
authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context)
|
||||||
let rent =
|
}
|
||||||
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
|
SystemInstruction::UpgradeNonceAccount => {
|
||||||
withdraw_nonce_account(
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
0,
|
let mut nonce_account =
|
||||||
lamports,
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
1,
|
if !system_program::check_id(nonce_account.get_owner()) {
|
||||||
&rent,
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
&signers,
|
|
||||||
invoke_context,
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
SystemInstruction::InitializeNonceAccount(authorized) => {
|
if !nonce_account.is_writable() {
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
return Err(InstructionError::InvalidArgument);
|
||||||
let mut me =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
if recent_blockhashes.is_empty() {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"Initialize nonce account: recent blockhash list is empty",
|
|
||||||
);
|
|
||||||
return Err(SystemError::NonceNoRecentBlockhashes.into());
|
|
||||||
}
|
|
||||||
let rent =
|
|
||||||
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
|
|
||||||
initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
|
|
||||||
}
|
}
|
||||||
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
|
let nonce_versions: nonce::state::Versions = nonce_account.get_state()?;
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
match nonce_versions.upgrade() {
|
||||||
let mut me =
|
None => Err(InstructionError::InvalidArgument),
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
|
||||||
authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context)
|
|
||||||
}
|
|
||||||
SystemInstruction::UpgradeNonceAccount => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
|
||||||
let mut nonce_account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
if !system_program::check_id(nonce_account.get_owner()) {
|
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
|
||||||
}
|
|
||||||
if !nonce_account.is_writable() {
|
|
||||||
return Err(InstructionError::InvalidArgument);
|
|
||||||
}
|
|
||||||
let nonce_versions: nonce::state::Versions = nonce_account.get_state()?;
|
|
||||||
match nonce_versions.upgrade() {
|
|
||||||
None => Err(InstructionError::InvalidArgument),
|
|
||||||
Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SystemInstruction::Allocate { space } => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
|
||||||
let mut account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
let address = Address::create(
|
|
||||||
transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
|
||||||
)?,
|
|
||||||
None,
|
|
||||||
invoke_context,
|
|
||||||
)?;
|
|
||||||
allocate(&mut account, &address, space, &signers, invoke_context)
|
|
||||||
}
|
|
||||||
SystemInstruction::AllocateWithSeed {
|
|
||||||
base,
|
|
||||||
seed,
|
|
||||||
space,
|
|
||||||
owner,
|
|
||||||
} => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
|
||||||
let mut account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
let address = Address::create(
|
|
||||||
transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
|
||||||
)?,
|
|
||||||
Some((&base, &seed, &owner)),
|
|
||||||
invoke_context,
|
|
||||||
)?;
|
|
||||||
allocate_and_assign(
|
|
||||||
&mut account,
|
|
||||||
&address,
|
|
||||||
space,
|
|
||||||
&owner,
|
|
||||||
&signers,
|
|
||||||
invoke_context,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SystemInstruction::AssignWithSeed { base, seed, owner } => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(1)?;
|
|
||||||
let mut account =
|
|
||||||
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
|
||||||
let address = Address::create(
|
|
||||||
transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
|
||||||
)?,
|
|
||||||
Some((&base, &seed, &owner)),
|
|
||||||
invoke_context,
|
|
||||||
)?;
|
|
||||||
assign(&mut account, &address, &owner, &signers, invoke_context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SystemInstruction::Allocate { space } => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
|
let mut account =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
let address = Address::create(
|
||||||
|
transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
|
)?,
|
||||||
|
None,
|
||||||
|
invoke_context,
|
||||||
|
)?;
|
||||||
|
allocate(&mut account, &address, space, &signers, invoke_context)
|
||||||
|
}
|
||||||
|
SystemInstruction::AllocateWithSeed {
|
||||||
|
base,
|
||||||
|
seed,
|
||||||
|
space,
|
||||||
|
owner,
|
||||||
|
} => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
|
let mut account =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
let address = Address::create(
|
||||||
|
transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
|
)?,
|
||||||
|
Some((&base, &seed, &owner)),
|
||||||
|
invoke_context,
|
||||||
|
)?;
|
||||||
|
allocate_and_assign(
|
||||||
|
&mut account,
|
||||||
|
&address,
|
||||||
|
space,
|
||||||
|
&owner,
|
||||||
|
&signers,
|
||||||
|
invoke_context,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SystemInstruction::AssignWithSeed { base, seed, owner } => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(1)?;
|
||||||
|
let mut account =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
let address = Address::create(
|
||||||
|
transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
|
||||||
|
)?,
|
||||||
|
Some((&base, &seed, &owner)),
|
||||||
|
invoke_context,
|
||||||
|
)?;
|
||||||
|
assign(&mut account, &address, &owner, &signers, invoke_context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -609,7 +603,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
)
|
)
|
||||||
|
@ -1599,7 +1593,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Ok(()),
|
Ok(()),
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context: &mut InvokeContext| {
|
|invoke_context: &mut InvokeContext| {
|
||||||
invoke_context.blockhash = hash(&serialize(&0).unwrap());
|
invoke_context.blockhash = hash(&serialize(&0).unwrap());
|
||||||
},
|
},
|
||||||
|
@ -1946,7 +1940,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Err(SystemError::NonceNoRecentBlockhashes.into()),
|
Err(SystemError::NonceNoRecentBlockhashes.into()),
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context: &mut InvokeContext| {
|
|invoke_context: &mut InvokeContext| {
|
||||||
invoke_context.blockhash = hash(&serialize(&0).unwrap());
|
invoke_context.blockhash = hash(&serialize(&0).unwrap());
|
||||||
},
|
},
|
||||||
|
|
|
@ -108,7 +108,7 @@ fn bench_process_vote_instruction(
|
||||||
transaction_accounts.clone(),
|
transaction_accounts.clone(),
|
||||||
instruction_account_metas.clone(),
|
instruction_account_metas.clone(),
|
||||||
Ok(()),
|
Ok(()),
|
||||||
solana_vote_program::vote_processor::process_instruction,
|
solana_vote_program::vote_processor::Entrypoint::vm,
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,209 +54,198 @@ fn process_authorize_with_seed_instruction(
|
||||||
// units; can consume based on instructions in the future like `bpf_loader` does.
|
// units; can consume based on instructions in the future like `bpf_loader` does.
|
||||||
pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100;
|
pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100;
|
||||||
|
|
||||||
declare_process_instruction!(
|
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
|
||||||
process_instruction,
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
DEFAULT_COMPUTE_UNITS,
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|invoke_context| {
|
let data = instruction_context.get_instruction_data();
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
|
||||||
let data = instruction_context.get_instruction_data();
|
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
|
|
||||||
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
if *me.get_owner() != id() {
|
if *me.get_owner() != id() {
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
let signers = instruction_context.get_signers(transaction_context)?;
|
||||||
|
match limited_deserialize(data)? {
|
||||||
|
VoteInstruction::InitializeAccount(vote_init) => {
|
||||||
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
||||||
|
if !rent.is_exempt(me.get_lamports(), me.get_data().len()) {
|
||||||
|
return Err(InstructionError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
vote_state::initialize_account(
|
||||||
|
&mut me,
|
||||||
|
&vote_init,
|
||||||
|
&signers,
|
||||||
|
&clock,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||||
|
vote_state::authorize(
|
||||||
|
&mut me,
|
||||||
|
&voter_pubkey,
|
||||||
|
vote_authorize,
|
||||||
|
&signers,
|
||||||
|
&clock,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::AuthorizeWithSeed(args) => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
|
process_authorize_with_seed_instruction(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
transaction_context,
|
||||||
|
&mut me,
|
||||||
|
&args.new_authority,
|
||||||
|
args.authorization_type,
|
||||||
|
&args.current_authority_derived_key_owner,
|
||||||
|
args.current_authority_derived_key_seed.as_str(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::AuthorizeCheckedWithSeed(args) => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
|
let new_authority = transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
||||||
|
)?;
|
||||||
|
if !instruction_context.is_instruction_account_signer(3)? {
|
||||||
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
process_authorize_with_seed_instruction(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
transaction_context,
|
||||||
|
&mut me,
|
||||||
|
new_authority,
|
||||||
|
args.authorization_type,
|
||||||
|
&args.current_authority_derived_key_owner,
|
||||||
|
args.current_authority_derived_key_seed.as_str(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::UpdateValidatorIdentity => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
let node_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
|
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
||||||
|
)?;
|
||||||
|
vote_state::update_validator_identity(
|
||||||
|
&mut me,
|
||||||
|
node_pubkey,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::UpdateCommission(commission) => {
|
||||||
|
if invoke_context.feature_set.is_active(
|
||||||
|
&feature_set::commission_updates_only_allowed_in_first_half_of_epoch::id(),
|
||||||
|
) {
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let epoch_schedule = sysvar_cache.get_epoch_schedule()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
if !vote_state::is_commission_update_allowed(clock.slot, &epoch_schedule) {
|
||||||
|
return Err(VoteError::CommissionUpdateTooLate.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vote_state::update_commission(
|
||||||
|
&mut me,
|
||||||
|
commission,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => {
|
||||||
|
let slot_hashes =
|
||||||
|
get_sysvar_with_account_check::slot_hashes(invoke_context, instruction_context, 1)?;
|
||||||
|
let clock =
|
||||||
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||||
|
vote_state::process_vote_with_account(
|
||||||
|
&mut me,
|
||||||
|
&slot_hashes,
|
||||||
|
&clock,
|
||||||
|
&vote,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::UpdateVoteState(vote_state_update)
|
||||||
|
| VoteInstruction::UpdateVoteStateSwitch(vote_state_update, _) => {
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
vote_state::process_vote_state_update(
|
||||||
|
&mut me,
|
||||||
|
slot_hashes.slot_hashes(),
|
||||||
|
&clock,
|
||||||
|
vote_state_update,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::CompactUpdateVoteState(vote_state_update)
|
||||||
|
| VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
vote_state::process_vote_state_update(
|
||||||
|
&mut me,
|
||||||
|
slot_hashes.slot_hashes(),
|
||||||
|
&clock,
|
||||||
|
vote_state_update,
|
||||||
|
&signers,
|
||||||
|
&invoke_context.feature_set,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let signers = instruction_context.get_signers(transaction_context)?;
|
VoteInstruction::Withdraw(lamports) => {
|
||||||
match limited_deserialize(data)? {
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
VoteInstruction::InitializeAccount(vote_init) => {
|
let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
|
||||||
let rent =
|
let clock_sysvar = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
|
||||||
if !rent.is_exempt(me.get_lamports(), me.get_data().len()) {
|
drop(me);
|
||||||
return Err(InstructionError::InsufficientFunds);
|
vote_state::withdraw(
|
||||||
}
|
transaction_context,
|
||||||
let clock =
|
instruction_context,
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
0,
|
||||||
vote_state::initialize_account(
|
lamports,
|
||||||
&mut me,
|
1,
|
||||||
&vote_init,
|
&signers,
|
||||||
&signers,
|
&rent_sysvar,
|
||||||
&clock,
|
&clock_sysvar,
|
||||||
&invoke_context.feature_set,
|
&invoke_context.feature_set,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
|
VoteInstruction::AuthorizeChecked(vote_authorize) => {
|
||||||
let clock =
|
if invoke_context
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
.feature_set
|
||||||
vote_state::authorize(
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
&mut me,
|
{
|
||||||
&voter_pubkey,
|
|
||||||
vote_authorize,
|
|
||||||
&signers,
|
|
||||||
&clock,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::AuthorizeWithSeed(args) => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
|
||||||
process_authorize_with_seed_instruction(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
transaction_context,
|
|
||||||
&mut me,
|
|
||||||
&args.new_authority,
|
|
||||||
args.authorization_type,
|
|
||||||
&args.current_authority_derived_key_owner,
|
|
||||||
args.current_authority_derived_key_seed.as_str(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::AuthorizeCheckedWithSeed(args) => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
let new_authority = transaction_context.get_key_of_account_at_index(
|
let voter_pubkey = transaction_context.get_key_of_account_at_index(
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
||||||
)?;
|
)?;
|
||||||
if !instruction_context.is_instruction_account_signer(3)? {
|
if !instruction_context.is_instruction_account_signer(3)? {
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
process_authorize_with_seed_instruction(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
transaction_context,
|
|
||||||
&mut me,
|
|
||||||
new_authority,
|
|
||||||
args.authorization_type,
|
|
||||||
&args.current_authority_derived_key_owner,
|
|
||||||
args.current_authority_derived_key_seed.as_str(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::UpdateValidatorIdentity => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let node_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
|
|
||||||
)?;
|
|
||||||
vote_state::update_validator_identity(
|
|
||||||
&mut me,
|
|
||||||
node_pubkey,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::UpdateCommission(commission) => {
|
|
||||||
if invoke_context.feature_set.is_active(
|
|
||||||
&feature_set::commission_updates_only_allowed_in_first_half_of_epoch::id(),
|
|
||||||
) {
|
|
||||||
let sysvar_cache = invoke_context.get_sysvar_cache();
|
|
||||||
let epoch_schedule = sysvar_cache.get_epoch_schedule()?;
|
|
||||||
let clock = sysvar_cache.get_clock()?;
|
|
||||||
if !vote_state::is_commission_update_allowed(clock.slot, &epoch_schedule) {
|
|
||||||
return Err(VoteError::CommissionUpdateTooLate.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vote_state::update_commission(
|
|
||||||
&mut me,
|
|
||||||
commission,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => {
|
|
||||||
let slot_hashes = get_sysvar_with_account_check::slot_hashes(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
let clock =
|
let clock =
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||||
vote_state::process_vote_with_account(
|
vote_state::authorize(
|
||||||
&mut me,
|
&mut me,
|
||||||
&slot_hashes,
|
voter_pubkey,
|
||||||
|
vote_authorize,
|
||||||
|
&signers,
|
||||||
&clock,
|
&clock,
|
||||||
&vote,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
&invoke_context.feature_set,
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
VoteInstruction::UpdateVoteState(vote_state_update)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
| VoteInstruction::UpdateVoteStateSwitch(vote_state_update, _) => {
|
|
||||||
let sysvar_cache = invoke_context.get_sysvar_cache();
|
|
||||||
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
|
||||||
let clock = sysvar_cache.get_clock()?;
|
|
||||||
vote_state::process_vote_state_update(
|
|
||||||
&mut me,
|
|
||||||
slot_hashes.slot_hashes(),
|
|
||||||
&clock,
|
|
||||||
vote_state_update,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::CompactUpdateVoteState(vote_state_update)
|
|
||||||
| VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
|
|
||||||
let sysvar_cache = invoke_context.get_sysvar_cache();
|
|
||||||
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
|
||||||
let clock = sysvar_cache.get_clock()?;
|
|
||||||
vote_state::process_vote_state_update(
|
|
||||||
&mut me,
|
|
||||||
slot_hashes.slot_hashes(),
|
|
||||||
&clock,
|
|
||||||
vote_state_update,
|
|
||||||
&signers,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
VoteInstruction::Withdraw(lamports) => {
|
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
|
||||||
let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
|
|
||||||
let clock_sysvar = invoke_context.get_sysvar_cache().get_clock()?;
|
|
||||||
|
|
||||||
drop(me);
|
|
||||||
vote_state::withdraw(
|
|
||||||
transaction_context,
|
|
||||||
instruction_context,
|
|
||||||
0,
|
|
||||||
lamports,
|
|
||||||
1,
|
|
||||||
&signers,
|
|
||||||
&rent_sysvar,
|
|
||||||
&clock_sysvar,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
VoteInstruction::AuthorizeChecked(vote_authorize) => {
|
|
||||||
if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
|
||||||
{
|
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
|
||||||
let voter_pubkey = transaction_context.get_key_of_account_at_index(
|
|
||||||
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
|
|
||||||
)?;
|
|
||||||
if !instruction_context.is_instruction_account_signer(3)? {
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
|
||||||
invoke_context,
|
|
||||||
instruction_context,
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
vote_state::authorize(
|
|
||||||
&mut me,
|
|
||||||
voter_pubkey,
|
|
||||||
vote_authorize,
|
|
||||||
&signers,
|
|
||||||
&clock,
|
|
||||||
&invoke_context.feature_set,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Err(InstructionError::InvalidInstructionData)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -320,7 +309,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
|_invoke_context| {},
|
|_invoke_context| {},
|
||||||
)
|
)
|
||||||
|
@ -339,7 +328,7 @@ mod tests {
|
||||||
transaction_accounts,
|
transaction_accounts,
|
||||||
instruction_accounts,
|
instruction_accounts,
|
||||||
expected_result,
|
expected_result,
|
||||||
super::process_instruction,
|
Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default());
|
invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default());
|
||||||
},
|
},
|
||||||
|
|
|
@ -130,7 +130,7 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(),
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 0, |invoke_context| {
|
declare_process_instruction!(Entrypoint, 0, |invoke_context| {
|
||||||
// Consume compute units if feature `native_programs_consume_cu` is activated
|
// Consume compute units if feature `native_programs_consume_cu` is activated
|
||||||
let native_programs_consume_cu = invoke_context
|
let native_programs_consume_cu = invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
|
|
|
@ -125,13 +125,13 @@ fn do_bench_transactions(
|
||||||
// freeze bank so that slot hashes is populated
|
// freeze bank so that slot hashes is populated
|
||||||
bank.freeze();
|
bank.freeze();
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), 1);
|
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), 1);
|
||||||
bank.add_mockup_builtin(Pubkey::from(BUILTIN_PROGRAM_ID), process_instruction);
|
bank.add_mockup_builtin(Pubkey::from(BUILTIN_PROGRAM_ID), MockBuiltin::vm);
|
||||||
bank.add_builtin_account("solana_noop_program", &Pubkey::from(NOOP_PROGRAM_ID), false);
|
bank.add_builtin_account("solana_noop_program", &Pubkey::from(NOOP_PROGRAM_ID), false);
|
||||||
let bank = Arc::new(bank);
|
let bank = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(bank.clone());
|
let bank_client = BankClient::new_shared(bank.clone());
|
||||||
|
|
|
@ -107,7 +107,7 @@ use {
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
|
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
|
||||||
compute_budget::{self, ComputeBudget},
|
compute_budget::{self, ComputeBudget},
|
||||||
invoke_context::ProcessInstructionWithContext,
|
invoke_context::BuiltinFunctionWithContext,
|
||||||
loaded_programs::{
|
loaded_programs::{
|
||||||
LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
|
LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
|
||||||
LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET,
|
LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||||
|
@ -7885,12 +7885,12 @@ impl Bank {
|
||||||
pub fn add_mockup_builtin(
|
pub fn add_mockup_builtin(
|
||||||
&mut self,
|
&mut self,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
entrypoint: ProcessInstructionWithContext,
|
builtin_function: BuiltinFunctionWithContext,
|
||||||
) {
|
) {
|
||||||
self.add_builtin(
|
self.add_builtin(
|
||||||
program_id,
|
program_id,
|
||||||
"mockup".to_string(),
|
"mockup".to_string(),
|
||||||
LoadedProgram::new_builtin(self.slot, 0, entrypoint),
|
LoadedProgram::new_builtin(self.slot, 0, builtin_function),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -653,7 +653,7 @@ fn assert_capitalization_diff(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
|
||||||
// Default for all tests which don't bring their own processor
|
// Default for all tests which don't bring their own processor
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
@ -1246,7 +1246,7 @@ fn test_rent_complex() {
|
||||||
Deduction,
|
Deduction,
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -1281,7 +1281,7 @@ fn test_rent_complex() {
|
||||||
root_bank.restore_old_behavior_for_fragile_tests();
|
root_bank.restore_old_behavior_for_fragile_tests();
|
||||||
let root_bank = Arc::new(root_bank);
|
let root_bank = Arc::new(root_bank);
|
||||||
let mut bank = create_child_bank_for_rent_test(root_bank, &genesis_config);
|
let mut bank = create_child_bank_for_rent_test(root_bank, &genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
assert_eq!(bank.last_blockhash(), genesis_config.hash());
|
assert_eq!(bank.last_blockhash(), genesis_config.hash());
|
||||||
|
|
||||||
|
@ -4684,7 +4684,7 @@ fn test_add_builtin() {
|
||||||
fn mock_vote_program_id() -> Pubkey {
|
fn mock_vote_program_id() -> Pubkey {
|
||||||
Pubkey::from([42u8; 32])
|
Pubkey::from([42u8; 32])
|
||||||
}
|
}
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
let program_id = instruction_context.get_last_program_key(transaction_context)?;
|
||||||
|
@ -4695,7 +4695,7 @@ fn test_add_builtin() {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
||||||
bank.add_mockup_builtin(mock_vote_program_id(), process_instruction);
|
bank.add_mockup_builtin(mock_vote_program_id(), MockBuiltin::vm);
|
||||||
assert!(bank.get_account(&mock_vote_program_id()).is_some());
|
assert!(bank.get_account(&mock_vote_program_id()).is_some());
|
||||||
|
|
||||||
let mock_account = Keypair::new();
|
let mock_account = Keypair::new();
|
||||||
|
@ -4740,7 +4740,7 @@ fn test_add_duplicate_static_program() {
|
||||||
} = create_genesis_config_with_leader(500, &solana_sdk::pubkey::new_rand(), 0);
|
} = create_genesis_config_with_leader(500, &solana_sdk::pubkey::new_rand(), 0);
|
||||||
let bank = Bank::new_for_tests(&genesis_config);
|
let bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4771,7 +4771,7 @@ fn test_add_duplicate_static_program() {
|
||||||
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
||||||
|
|
||||||
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
|
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
let new_vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
|
let new_vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
|
||||||
// Vote loader account should not be updated since it was included in the genesis config.
|
// Vote loader account should not be updated since it was included in the genesis config.
|
||||||
assert_eq!(vote_loader_account.data(), new_vote_loader_account.data());
|
assert_eq!(vote_loader_account.data(), new_vote_loader_account.data());
|
||||||
|
@ -4789,7 +4789,7 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
|
||||||
for pass in 0..5 {
|
for pass in 0..5 {
|
||||||
let mut bank = create_simple_test_bank(500);
|
let mut bank = create_simple_test_bank(500);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4825,12 +4825,12 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
|
||||||
bank.add_builtin(
|
bank.add_builtin(
|
||||||
vote_id,
|
vote_id,
|
||||||
"mock_program1".to_string(),
|
"mock_program1".to_string(),
|
||||||
LoadedProgram::new_builtin(0, 0, process_instruction),
|
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
|
||||||
);
|
);
|
||||||
bank.add_builtin(
|
bank.add_builtin(
|
||||||
stake_id,
|
stake_id,
|
||||||
"mock_program2".to_string(),
|
"mock_program2".to_string(),
|
||||||
LoadedProgram::new_builtin(0, 0, process_instruction),
|
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
let stakes = bank.stakes_cache.stakes();
|
let stakes = bank.stakes_cache.stakes();
|
||||||
|
@ -4854,8 +4854,8 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
|
||||||
// Re-adding builtin programs should be no-op
|
// Re-adding builtin programs should be no-op
|
||||||
bank.update_accounts_hash_for_tests();
|
bank.update_accounts_hash_for_tests();
|
||||||
let old_hash = bank.get_accounts_hash().unwrap();
|
let old_hash = bank.get_accounts_hash().unwrap();
|
||||||
bank.add_mockup_builtin(vote_id, process_instruction);
|
bank.add_mockup_builtin(vote_id, MockBuiltin::vm);
|
||||||
bank.add_mockup_builtin(stake_id, process_instruction);
|
bank.add_mockup_builtin(stake_id, MockBuiltin::vm);
|
||||||
add_root_and_flush_write_cache(&bank);
|
add_root_and_flush_write_cache(&bank);
|
||||||
bank.update_accounts_hash_for_tests();
|
bank.update_accounts_hash_for_tests();
|
||||||
let new_hash = bank.get_accounts_hash().unwrap();
|
let new_hash = bank.get_accounts_hash().unwrap();
|
||||||
|
@ -6086,7 +6086,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -6107,7 +6107,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
bank.add_mockup_builtin(mock_program_id, process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
let from_pubkey = solana_sdk::pubkey::new_rand();
|
let from_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
let to_pubkey = solana_sdk::pubkey::new_rand();
|
let to_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -6143,7 +6143,7 @@ fn test_transaction_with_program_ids_passed_to_programs() {
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
bank.add_mockup_builtin(mock_program_id, process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
let from_pubkey = solana_sdk::pubkey::new_rand();
|
let from_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
let to_pubkey = solana_sdk::pubkey::new_rand();
|
let to_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -6198,7 +6198,7 @@ fn test_account_ids_after_program_ids() {
|
||||||
let slot = bank.slot().saturating_add(1);
|
let slot = bank.slot().saturating_add(1);
|
||||||
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
||||||
|
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
let result = bank.process_transaction(&tx);
|
let result = bank.process_transaction(&tx);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
let account = bank.get_account(&solana_vote_program::id()).unwrap();
|
let account = bank.get_account(&solana_vote_program::id()).unwrap();
|
||||||
|
@ -6248,7 +6248,7 @@ fn test_duplicate_account_key() {
|
||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
|
|
||||||
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -6277,7 +6277,7 @@ fn test_process_transaction_with_too_many_account_locks() {
|
||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
|
|
||||||
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -6310,7 +6310,7 @@ fn test_program_id_as_payer() {
|
||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
|
|
||||||
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -6356,7 +6356,7 @@ fn test_ref_account_key_after_program_id() {
|
||||||
let slot = bank.slot().saturating_add(1);
|
let slot = bank.slot().saturating_add(1);
|
||||||
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot);
|
||||||
|
|
||||||
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
|
bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm);
|
||||||
|
|
||||||
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -6390,7 +6390,7 @@ fn test_fuzz_instructions() {
|
||||||
bank.add_builtin(
|
bank.add_builtin(
|
||||||
key,
|
key,
|
||||||
name.clone(),
|
name.clone(),
|
||||||
LoadedProgram::new_builtin(0, 0, process_instruction),
|
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
|
||||||
);
|
);
|
||||||
(key, name.as_bytes().to_vec())
|
(key, name.as_bytes().to_vec())
|
||||||
})
|
})
|
||||||
|
@ -6584,7 +6584,7 @@ fn test_bank_hash_consistency() {
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_same_program_id_uses_unique_executable_accounts() {
|
fn test_same_program_id_uses_unique_executable_accounts() {
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
instruction_context
|
instruction_context
|
||||||
|
@ -6597,7 +6597,7 @@ fn test_same_program_id_uses_unique_executable_accounts() {
|
||||||
|
|
||||||
// Add a new program
|
// Add a new program
|
||||||
let program1_pubkey = solana_sdk::pubkey::new_rand();
|
let program1_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
bank.add_mockup_builtin(program1_pubkey, process_instruction);
|
bank.add_mockup_builtin(program1_pubkey, MockBuiltin::vm);
|
||||||
|
|
||||||
// Add a new program owned by the first
|
// Add a new program owned by the first
|
||||||
let program2_pubkey = solana_sdk::pubkey::new_rand();
|
let program2_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -6814,13 +6814,13 @@ fn test_add_builtin_no_overwrite() {
|
||||||
|
|
||||||
Arc::get_mut(&mut bank)
|
Arc::get_mut(&mut bank)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_mockup_builtin(program_id, process_instruction);
|
.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
||||||
|
|
||||||
let mut bank = Arc::new(new_from_parent(bank));
|
let mut bank = Arc::new(new_from_parent(bank));
|
||||||
Arc::get_mut(&mut bank)
|
Arc::get_mut(&mut bank)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_mockup_builtin(program_id, process_instruction);
|
.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6838,13 +6838,13 @@ fn test_add_builtin_loader_no_overwrite() {
|
||||||
|
|
||||||
Arc::get_mut(&mut bank)
|
Arc::get_mut(&mut bank)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_mockup_builtin(loader_id, process_instruction);
|
.add_mockup_builtin(loader_id, MockBuiltin::vm);
|
||||||
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
||||||
|
|
||||||
let mut bank = Arc::new(new_from_parent(bank));
|
let mut bank = Arc::new(new_from_parent(bank));
|
||||||
Arc::get_mut(&mut bank)
|
Arc::get_mut(&mut bank)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_mockup_builtin(loader_id, process_instruction);
|
.add_mockup_builtin(loader_id, MockBuiltin::vm);
|
||||||
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7403,7 +7403,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
|
||||||
],
|
],
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
Ok(()),
|
Ok(()),
|
||||||
solana_bpf_loader_program::process_instruction,
|
solana_bpf_loader_program::Entrypoint::vm,
|
||||||
|invoke_context| {
|
|invoke_context| {
|
||||||
invoke_context
|
invoke_context
|
||||||
.programs_modified_by_tx
|
.programs_modified_by_tx
|
||||||
|
@ -9708,7 +9708,7 @@ fn test_tx_return_data() {
|
||||||
);
|
);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
let transaction_context = &mut invoke_context.transaction_context;
|
let transaction_context = &mut invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|
@ -9726,7 +9726,7 @@ fn test_tx_return_data() {
|
||||||
|
|
||||||
let mock_program_id = Pubkey::from([2u8; 32]);
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
||||||
let blockhash = bank.last_blockhash();
|
let blockhash = bank.last_blockhash();
|
||||||
bank.add_mockup_builtin(mock_program_id, process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
for index in [
|
for index in [
|
||||||
None,
|
None,
|
||||||
|
@ -9906,7 +9906,7 @@ fn test_transfer_sysvar() {
|
||||||
);
|
);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
instruction_context
|
instruction_context
|
||||||
|
@ -9916,7 +9916,7 @@ fn test_transfer_sysvar() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
bank.add_mockup_builtin(program_id, process_instruction);
|
bank.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
let blockhash = bank.last_blockhash();
|
let blockhash = bank.last_blockhash();
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
@ -10115,7 +10115,7 @@ fn test_compute_budget_program_noop() {
|
||||||
);
|
);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -10128,7 +10128,7 @@ fn test_compute_budget_program_noop() {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
bank.add_mockup_builtin(program_id, process_instruction);
|
bank.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
|
@ -10158,7 +10158,7 @@ fn test_compute_request_instruction() {
|
||||||
);
|
);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -10171,7 +10171,7 @@ fn test_compute_request_instruction() {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
bank.add_mockup_builtin(program_id, process_instruction);
|
bank.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&[
|
&[
|
||||||
|
@ -10208,7 +10208,7 @@ fn test_failed_compute_request_instruction() {
|
||||||
bank.transfer(10, &mint_keypair, &payer1_keypair.pubkey())
|
bank.transfer(10, &mint_keypair, &payer1_keypair.pubkey())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
|
||||||
let compute_budget = invoke_context.get_compute_budget();
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*compute_budget,
|
*compute_budget,
|
||||||
|
@ -10221,7 +10221,7 @@ fn test_failed_compute_request_instruction() {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
let program_id = solana_sdk::pubkey::new_rand();
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
bank.add_mockup_builtin(program_id, process_instruction);
|
bank.add_mockup_builtin(program_id, MockBuiltin::vm);
|
||||||
|
|
||||||
// This message will not be executed because the compute budget request is invalid
|
// This message will not be executed because the compute budget request is invalid
|
||||||
let message0 = Message::new(
|
let message0 = Message::new(
|
||||||
|
@ -10825,7 +10825,7 @@ enum MockTransferInstruction {
|
||||||
Transfer(u64),
|
Transfer(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(mock_transfer_process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockTransferBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -10908,7 +10908,7 @@ fn test_invalid_rent_state_changes_existing_accounts() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm);
|
||||||
let recent_blockhash = bank.last_blockhash();
|
let recent_blockhash = bank.last_blockhash();
|
||||||
|
|
||||||
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
|
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
|
||||||
|
@ -10991,7 +10991,7 @@ fn test_invalid_rent_state_changes_new_accounts() {
|
||||||
let rent_exempt_minimum = genesis_config.rent.minimum_balance(account_data_size);
|
let rent_exempt_minimum = genesis_config.rent.minimum_balance(account_data_size);
|
||||||
|
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm);
|
||||||
let recent_blockhash = bank.last_blockhash();
|
let recent_blockhash = bank.last_blockhash();
|
||||||
|
|
||||||
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
|
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
|
||||||
|
@ -11050,7 +11050,7 @@ fn test_drained_created_account() {
|
||||||
let created_keypair = Keypair::new();
|
let created_keypair = Keypair::new();
|
||||||
|
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm);
|
||||||
let recent_blockhash = bank.last_blockhash();
|
let recent_blockhash = bank.last_blockhash();
|
||||||
|
|
||||||
// Create and drain a small data size account
|
// Create and drain a small data size account
|
||||||
|
@ -11578,7 +11578,7 @@ enum MockReallocInstruction {
|
||||||
Realloc(usize, u64, Pubkey),
|
Realloc(usize, u64, Pubkey),
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_process_instruction!(mock_realloc_process_instruction, 1, |invoke_context| {
|
declare_process_instruction!(MockReallocBuiltin, 1, |invoke_context| {
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
|
@ -11658,7 +11658,7 @@ fn test_resize_and_rent() {
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
let mock_program_id = Pubkey::new_unique();
|
let mock_program_id = Pubkey::new_unique();
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockReallocBuiltin::vm);
|
||||||
let recent_blockhash = bank.last_blockhash();
|
let recent_blockhash = bank.last_blockhash();
|
||||||
|
|
||||||
let account_data_size_small = 1024;
|
let account_data_size_small = 1024;
|
||||||
|
@ -11929,7 +11929,7 @@ fn test_accounts_data_size_and_resize_transactions() {
|
||||||
} = genesis_utils::create_genesis_config(100 * LAMPORTS_PER_SOL);
|
} = genesis_utils::create_genesis_config(100 * LAMPORTS_PER_SOL);
|
||||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||||
let mock_program_id = Pubkey::new_unique();
|
let mock_program_id = Pubkey::new_unique();
|
||||||
bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction);
|
bank.add_mockup_builtin(mock_program_id, MockReallocBuiltin::vm);
|
||||||
|
|
||||||
let recent_blockhash = bank.last_blockhash();
|
let recent_blockhash = bank.last_blockhash();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
solana_program_runtime::invoke_context::ProcessInstructionWithContext,
|
solana_program_runtime::invoke_context::BuiltinFunctionWithContext,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, feature_set, pubkey::Pubkey,
|
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, feature_set, pubkey::Pubkey,
|
||||||
},
|
},
|
||||||
|
@ -10,7 +10,7 @@ pub struct BuiltinPrototype {
|
||||||
pub feature_id: Option<Pubkey>,
|
pub feature_id: Option<Pubkey>,
|
||||||
pub program_id: Pubkey,
|
pub program_id: Pubkey,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub entrypoint: ProcessInstructionWithContext,
|
pub entrypoint: BuiltinFunctionWithContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for BuiltinPrototype {
|
impl std::fmt::Debug for BuiltinPrototype {
|
||||||
|
@ -27,7 +27,7 @@ impl std::fmt::Debug for BuiltinPrototype {
|
||||||
impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
|
impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
|
||||||
fn example() -> Self {
|
fn example() -> Self {
|
||||||
// BuiltinPrototype isn't serializable by definition.
|
// BuiltinPrototype isn't serializable by definition.
|
||||||
solana_program_runtime::declare_process_instruction!(entrypoint, 0, |_invoke_context| {
|
solana_program_runtime::declare_process_instruction!(MockBuiltin, 0, |_invoke_context| {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
@ -35,7 +35,7 @@ impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: Pubkey::default(),
|
program_id: Pubkey::default(),
|
||||||
name: "",
|
name: "",
|
||||||
entrypoint,
|
entrypoint: MockBuiltin::vm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,66 +45,66 @@ pub static BUILTINS: &[BuiltinPrototype] = &[
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_system_program::id(),
|
program_id: solana_system_program::id(),
|
||||||
name: "system_program",
|
name: "system_program",
|
||||||
entrypoint: solana_system_program::system_processor::process_instruction,
|
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_vote_program::id(),
|
program_id: solana_vote_program::id(),
|
||||||
name: "vote_program",
|
name: "vote_program",
|
||||||
entrypoint: solana_vote_program::vote_processor::process_instruction,
|
entrypoint: solana_vote_program::vote_processor::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_stake_program::id(),
|
program_id: solana_stake_program::id(),
|
||||||
name: "stake_program",
|
name: "stake_program",
|
||||||
entrypoint: solana_stake_program::stake_instruction::process_instruction,
|
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_config_program::id(),
|
program_id: solana_config_program::id(),
|
||||||
name: "config_program",
|
name: "config_program",
|
||||||
entrypoint: solana_config_program::config_processor::process_instruction,
|
entrypoint: solana_config_program::config_processor::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: bpf_loader_deprecated::id(),
|
program_id: bpf_loader_deprecated::id(),
|
||||||
name: "solana_bpf_loader_deprecated_program",
|
name: "solana_bpf_loader_deprecated_program",
|
||||||
entrypoint: solana_bpf_loader_program::process_instruction,
|
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: bpf_loader::id(),
|
program_id: bpf_loader::id(),
|
||||||
name: "solana_bpf_loader_program",
|
name: "solana_bpf_loader_program",
|
||||||
entrypoint: solana_bpf_loader_program::process_instruction,
|
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: bpf_loader_upgradeable::id(),
|
program_id: bpf_loader_upgradeable::id(),
|
||||||
name: "solana_bpf_loader_upgradeable_program",
|
name: "solana_bpf_loader_upgradeable_program",
|
||||||
entrypoint: solana_bpf_loader_program::process_instruction,
|
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_sdk::compute_budget::id(),
|
program_id: solana_sdk::compute_budget::id(),
|
||||||
name: "compute_budget_program",
|
name: "compute_budget_program",
|
||||||
entrypoint: solana_compute_budget_program::process_instruction,
|
entrypoint: solana_compute_budget_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: None,
|
feature_id: None,
|
||||||
program_id: solana_sdk::address_lookup_table::program::id(),
|
program_id: solana_sdk::address_lookup_table::program::id(),
|
||||||
name: "address_lookup_table_program",
|
name: "address_lookup_table_program",
|
||||||
entrypoint: solana_address_lookup_table_program::processor::process_instruction,
|
entrypoint: solana_address_lookup_table_program::processor::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: Some(feature_set::zk_token_sdk_enabled::id()),
|
feature_id: Some(feature_set::zk_token_sdk_enabled::id()),
|
||||||
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
|
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
|
||||||
name: "zk_token_proof_program",
|
name: "zk_token_proof_program",
|
||||||
entrypoint: solana_zk_token_proof_program::process_instruction,
|
entrypoint: solana_zk_token_proof_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
BuiltinPrototype {
|
BuiltinPrototype {
|
||||||
feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()),
|
feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()),
|
||||||
program_id: solana_sdk::loader_v4::id(),
|
program_id: solana_sdk::loader_v4::id(),
|
||||||
name: "loader_v4",
|
name: "loader_v4",
|
||||||
entrypoint: solana_loader_v4_program::process_instruction,
|
entrypoint: solana_loader_v4_program::Entrypoint::vm,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue