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:
Alexander Meißner 2023-10-20 21:39:50 +02:00 committed by GitHub
parent dc3c827299
commit a5c7c999e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1387 additions and 1596 deletions

5
Cargo.lock generated
View File

@ -6640,6 +6640,7 @@ dependencies = [
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"solana_rbpf",
"test-case",
"thiserror",
"tokio",
@ -7625,9 +7626,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.7.2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196"
checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3"
dependencies = [
"byteorder",
"combine",

View File

@ -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-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_rbpf = "=0.7.2"
solana_rbpf = "=0.8.0"
spl-associated-token-account = "=2.2.0"
spl-instruction-padding = "0.1"
spl-memo = "=4.0.0"

View File

@ -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
Ok(())
});
@ -3002,7 +3002,7 @@ pub mod tests {
let mock_program_id = solana_sdk::pubkey::new_rand();
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(
&[Instruction::new_with_bincode(
@ -3023,7 +3023,7 @@ pub mod tests {
let bankhash_ok = bank.hash();
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 err = invoke_context
@ -3043,7 +3043,7 @@ pub mod tests {
(0..get_instruction_errors().len()).for_each(|err| {
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(
&[Instruction::new_with_bincode(

View File

@ -12,9 +12,10 @@ use {
solana_measure::measure::Measure,
solana_rbpf::{
ebpf::MM_HEAP_START,
elf::SBPFVersion,
error::{EbpfError, ProgramResult},
memory_region::MemoryMapping,
vm::{BuiltinFunction, Config, ContextObject, ProgramResult},
program::{BuiltinFunction, SBPFVersion},
vm::{Config, ContextObject, EbpfVm},
},
solana_sdk::{
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
#[macro_export]
macro_rules! declare_process_instruction {
($process_instruction:ident, $cu_to_consume:expr, |$invoke_context:ident| $inner:tt) => {
pub fn $process_instruction(
invoke_context: &mut $crate::invoke_context::InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping,
result: &mut $crate::solana_rbpf::vm::ProgramResult,
) {
fn process_instruction_inner(
$invoke_context: &mut $crate::invoke_context::InvokeContext,
) -> std::result::Result<(), solana_sdk::instruction::InstructionError> {
$inner
$crate::solana_rbpf::declare_builtin_function!(
$process_instruction,
fn rust(
invoke_context: &mut $crate::invoke_context::InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping,
) -> std::result::Result<u64, Box<dyn std::error::Error>> {
fn process_instruction_inner(
$invoke_context: &mut $crate::invoke_context::InvokeContext,
) -> 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
.find(&builtin_id)
.ok_or(InstructionError::UnsupportedProgramId)?;
let process_instruction = match &entry.program {
let function = match &entry.program {
LoadedProgramType::Builtin(program) => program
.get_function_registry()
.lookup_by_key(ENTRYPOINT_KEY)
.map(|(_name, process_instruction)| process_instruction),
.map(|(_name, function)| function),
_ => None,
}
.ok_or(InstructionError::UnsupportedProgramId)?;
@ -484,31 +487,41 @@ impl<'a> InvokeContext<'a> {
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
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 mut mock_memory_mapping =
MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V2).unwrap();
let mut result = ProgramResult::Ok(0);
process_instruction(
let empty_memory_mapping =
MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V1).unwrap();
let mut vm = EbpfVm::new(
self.programs_loaded_for_tx_batch
.environments
.program_runtime_v2
.clone(),
&SBPFVersion::V1,
// Removes lifetime tracking
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
empty_memory_mapping,
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(_) => {
stable_log::program_success(&logger, &program_id);
Ok(())
}
ProgramResult::Err(err) => {
stable_log::program_failure(&logger, &program_id, err.as_ref());
if let Some(err) = err.downcast_ref::<InstructionError>() {
Err(err.clone())
ProgramResult::Err(ref err) => {
if let EbpfError::SyscallError(syscall_error) = err {
if let Some(instruction_err) = syscall_error.downcast_ref::<InstructionError>()
{
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 {
stable_log::program_failure(&logger, &program_id, err);
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>,
instruction_account_metas: Vec<AccountMeta>,
expected_result: Result<(), InstructionError>,
process_instruction: ProcessInstructionWithContext,
builtin_function: BuiltinFunctionWithContext,
mut pre_adjustments: F,
mut post_adjustments: G,
) -> 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();
programs_loaded_for_tx_batch.replenish(
*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;
pre_adjustments(&mut invoke_context);
@ -782,7 +795,7 @@ mod tests {
const MOCK_BUILTIN_COMPUTE_UNIT_COST: u64 = 1;
declare_process_instruction!(
process_instruction,
MockBuiltin,
MOCK_BUILTIN_COMPUTE_UNIT_COST,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
@ -988,7 +1001,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
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;
@ -1134,7 +1147,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
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;

View File

@ -1,6 +1,6 @@
use {
crate::{
invoke_context::{InvokeContext, ProcessInstructionWithContext},
invoke_context::{BuiltinFunctionWithContext, InvokeContext},
timings::ExecuteDetailsTimings,
},
itertools::Itertools,
@ -8,9 +8,10 @@ use {
percentage::PercentageInteger,
solana_measure::measure::Measure,
solana_rbpf::{
elf::{Executable, FunctionRegistry},
elf::Executable,
program::{BuiltinProgram, FunctionRegistry},
verifier::RequisiteVerifier,
vm::{BuiltinProgram, Config},
vm::Config,
},
solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
@ -370,11 +371,11 @@ impl LoadedProgram {
pub fn new_builtin(
deployment_slot: Slot,
account_size: usize,
entrypoint: ProcessInstructionWithContext,
builtin_function: BuiltinFunctionWithContext,
) -> Self {
let mut function_registry = FunctionRegistry::default();
function_registry
.register_function_hashed(*b"entrypoint", entrypoint)
.register_function_hashed(*b"entrypoint", builtin_function)
.unwrap();
Self {
deployment_slot,
@ -949,7 +950,7 @@ mod tests {
},
assert_matches::assert_matches,
percentage::Percentage,
solana_rbpf::vm::BuiltinProgram,
solana_rbpf::program::BuiltinProgram,
solana_sdk::{
clock::{Epoch, Slot},
pubkey::Pubkey,

View File

@ -220,7 +220,7 @@ mod tests {
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 instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -271,7 +271,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
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())
.map(|index| {
@ -432,7 +432,7 @@ mod tests {
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 instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -500,7 +500,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
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![
AccountMeta::new(
@ -645,7 +645,7 @@ mod tests {
#[test]
fn test_precompile() {
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))
});
@ -684,7 +684,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
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_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();

View File

@ -101,10 +101,10 @@ pub fn program_success(log_collector: &Option<Rc<RefCell<LogCollector>>>, progra
/// ```notrust
/// "Program <address> failed: <program error details>"
/// ```
pub fn program_failure(
pub fn program_failure<E: std::fmt::Display>(
log_collector: &Option<Rc<RefCell<LogCollector>>>,
program_id: &Pubkey,
err: &dyn std::error::Error,
err: &E,
) {
ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err);
}

View File

@ -27,6 +27,7 @@ solana-program-runtime = { workspace = true }
solana-runtime = { workspace = true }
solana-sdk = { workspace = true }
solana-vote-program = { workspace = true }
solana_rbpf = { workspace = true }
test-case = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }

View File

@ -13,7 +13,7 @@ use {
solana_banks_server::banks_server::start_local_server,
solana_bpf_loader_program::serialization::serialize_parameters,
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,
},
solana_runtime::{
@ -66,6 +66,10 @@ pub use {
solana_banks_client::{BanksClient, BanksClientError},
solana_banks_interface::BanksTransactionResultWithMetadata,
solana_program_runtime::invoke_context::InvokeContext,
solana_rbpf::{
error::EbpfError,
vm::{get_runtime_environment_key, EbpfVm},
},
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) }
}
pub fn builtin_process_instruction(
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
pub fn invoke_builtin_function(
builtin_function: solana_sdk::entrypoint::ProcessInstruction,
invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
) -> Result<u64, Box<dyn std::error::Error>> {
set_invoke_context(invoke_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) };
// Execute the program
process_instruction(program_id, &account_infos, instruction_data).map_err(|err| {
let err: Box<dyn std::error::Error> = Box::new(InstructionError::from(u64::from(err)));
stable_log::program_failure(&log_collector, program_id, err.as_ref());
builtin_function(program_id, &account_infos, instruction_data).map_err(|err| {
let err = InstructionError::from(u64::from(err));
stable_log::program_failure(&log_collector, program_id, &err);
let err: Box<dyn std::error::Error> = Box::new(err);
err
})?;
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
/// use with `ProgramTest::add_program`
#[macro_export]
macro_rules! processor {
($process_instruction:expr) => {
Some(
|invoke_context, _arg0, _arg1, _arg2, _arg3, _arg4, _memory_mapping, result| {
*result = $crate::builtin_process_instruction($process_instruction, invoke_context)
.map(|_| 0)
($builtin_function:expr) => {
Some(|vm, _arg0, _arg1, _arg2, _arg3, _arg4| {
let vm = unsafe {
&mut *((vm as *mut u64).offset(-($crate::get_runtime_environment_key() as isize))
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();
},
)
})
};
}
@ -506,10 +514,10 @@ impl ProgramTest {
pub fn new(
program_name: &str,
program_id: Pubkey,
process_instruction: Option<ProcessInstructionWithContext>,
builtin_function: Option<BuiltinFunctionWithContext>,
) -> Self {
let mut me = Self::default();
me.add_program(program_name, program_id, process_instruction);
me.add_program(program_name, program_id, builtin_function);
me
}
@ -600,13 +608,13 @@ impl ProgramTest {
/// `program_name` will also be used to locate the SBF shared object in the current or fixtures
/// 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.
pub fn add_program(
&mut self,
program_name: &str,
program_id: Pubkey,
process_instruction: Option<ProcessInstructionWithContext>,
builtin_function: Option<BuiltinFunctionWithContext>,
) {
let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| {
let data = read_file(&program_file);
@ -680,7 +688,7 @@ impl ProgramTest {
};
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,
// use that as the program data.
(true, Some(file), _) => add_bpf(self, file),
@ -689,8 +697,8 @@ impl ProgramTest {
// processor function as is.
//
// TODO: figure out why tests hang if a processor panics when running native code.
(false, _, Some(process)) => {
self.add_builtin_program(program_name, program_id, process)
(false, _, Some(builtin_function)) => {
self.add_builtin_program(program_name, program_id, builtin_function)
}
// Invalid: `test-sbf` invocation with no matching SBF shared object.
@ -713,13 +721,13 @@ impl ProgramTest {
&mut self,
program_name: &str,
program_id: Pubkey,
process_instruction: ProcessInstructionWithContext,
builtin_function: BuiltinFunctionWithContext,
) {
info!("\"{}\" builtin program", program_name);
self.builtin_programs.push((
program_id,
program_name.to_string(),
LoadedProgram::new_builtin(0, program_name.len(), process_instruction),
LoadedProgram::new_builtin(0, program_name.len(), builtin_function),
));
}

View File

@ -1,6 +1,5 @@
#![allow(dead_code)]
use {
solana_address_lookup_table_program::processor::process_instruction,
solana_program_test::*,
solana_sdk::{
account::AccountSharedData,
@ -20,7 +19,11 @@ use {
};
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
}

View File

@ -1,7 +1,6 @@
use {
assert_matches::assert_matches,
common::{assert_ix_error, overwrite_slot_hashes_with_slots, setup_test_context},
solana_address_lookup_table_program::processor::process_instruction,
solana_program_test::*,
solana_sdk::{
address_lookup_table::{
@ -23,7 +22,11 @@ use {
mod common;
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(
feature_set::relax_authority_signer_check_for_lookup_table_creation::id(),
);

View File

@ -21,29 +21,25 @@ use {
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
match limited_deserialize(instruction_data)? {
ProgramInstruction::CreateLookupTable {
recent_slot,
bump_seed,
} => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed),
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),
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
match limited_deserialize(instruction_data)? {
ProgramInstruction::CreateLookupTable {
recent_slot,
bump_seed,
} => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed),
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),
}
);
});
fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> {
a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow)

View File

@ -1,7 +1,6 @@
#![allow(dead_code)]
use {
solana_bpf_loader_program::process_instruction,
solana_program_test::*,
solana_sdk::{
account::AccountSharedData,
@ -15,7 +14,7 @@ use {
};
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
}

View File

@ -18,12 +18,14 @@ use {
},
solana_rbpf::{
aligned_memory::AlignedMemory,
declare_builtin_function,
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
elf::Executable,
error::EbpfError,
error::{EbpfError, ProgramResult},
memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
program::BuiltinProgram,
verifier::RequisiteVerifier,
vm::{BuiltinProgram, ContextObject, EbpfVm, ProgramResult},
vm::{ContextObject, EbpfVm},
},
solana_sdk::{
account::WritableAccount,
@ -265,7 +267,7 @@ pub fn create_vm<'a, 'b>(
trace_log: Vec::new(),
})?;
Ok(EbpfVm::new(
program.get_config(),
program.get_loader().clone(),
program.get_sbpf_version(),
invoke_context,
memory_mapping,
@ -317,7 +319,7 @@ macro_rules! create_vm {
macro_rules! mock_create_vm {
($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
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(
&[0x95, 0, 0, 0, 0, 0, 0, 0],
loader,
@ -371,20 +373,22 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>(
})
}
pub fn process_instruction(
invoke_context: &mut InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut MemoryMapping,
result: &mut ProgramResult,
) {
*result = process_instruction_inner(invoke_context).into();
}
declare_builtin_function!(
Entrypoint,
fn rust(
invoke_context: &mut InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut MemoryMapping,
) -> 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,
) -> Result<u64, Box<dyn std::error::Error>> {
let log_collector = invoke_context.get_log_collector();
@ -1607,13 +1611,12 @@ fn execute<'a, 'b: 'a>(
}
ProgramResult::Err(mut error) => {
if direct_mapping {
if let Some(EbpfError::AccessViolation(
_pc,
if let EbpfError::AccessViolation(
AccessType::Store,
address,
_size,
_section_name,
)) = error.downcast_ref()
) = error
{
// 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
@ -1621,7 +1624,7 @@ fn execute<'a, 'b: 'a>(
if let Some((instruction_account_index, _)) = account_region_addrs
.iter()
.enumerate()
.find(|(_, vm_region)| vm_region.contains(address))
.find(|(_, vm_region)| vm_region.contains(&address))
{
let transaction_context = &invoke_context.transaction_context;
let instruction_context =
@ -1632,17 +1635,21 @@ fn execute<'a, 'b: 'a>(
instruction_account_index as IndexOfAccount,
)?;
error = Box::new(if account.is_executable() {
error = EbpfError::SyscallError(Box::new(if account.is_executable() {
InstructionError::ExecutableDataModified
} else if account.is_writable() {
InstructionError::ExternalAccountDataModified
} else {
InstructionError::ReadonlyDataModified
})
}));
}
}
}
Err(error)
Err(if let EbpfError::SyscallError(err) = error {
err
} else {
error.into()
})
}
_ => Ok(()),
}
@ -1790,7 +1797,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
test_utils::load_all_invoked_programs(invoke_context);
},
@ -2009,7 +2016,7 @@ mod tests {
vec![(program_id, program_account.clone())],
Vec::new(),
Err(InstructionError::ProgramFailedToComplete),
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
invoke_context.mock_set_remaining(0);
test_utils::load_all_invoked_programs(invoke_context);
@ -2555,7 +2562,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|_invoke_context| {},
|_invoke_context| {},
)

View File

@ -1,6 +1,6 @@
use {
super::*,
crate::{declare_syscall, serialization::account_data_region_memory_state},
crate::serialization::account_data_region_memory_state,
scopeguard::defer,
solana_program_runtime::invoke_context::SerializedAccountMetadata,
solana_rbpf::{
@ -455,10 +455,10 @@ trait SyscallInvokeSigned {
) -> Result<Vec<Pubkey>, Error>;
}
declare_syscall!(
declare_builtin_function!(
/// Cross-program invocation called from Rust
SyscallInvokeSignedRust,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
instruction_addr: u64,
account_infos_addr: u64,
@ -689,10 +689,10 @@ struct SolSignerSeedsC {
len: u64,
}
declare_syscall!(
declare_builtin_function!(
/// Cross-program invocation called from C
SyscallInvokeSignedC,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
instruction_addr: u64,
account_infos_addr: u64,
@ -1730,7 +1730,7 @@ mod tests {
invoke_context::SerializedAccountMetadata, with_mock_invoke_context,
},
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::{
account::{Account, AccountSharedData},

View File

@ -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
SyscallLog,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
addr: u64,
len: u64,
@ -36,10 +36,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Log 5 64-bit values
SyscallLogU64,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
arg1: u64,
arg2: u64,
@ -59,10 +59,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Log current compute consumption
SyscallLogBpfComputeUnits,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
_arg1: u64,
_arg2: u64,
@ -83,10 +83,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Log 5 64-bit values
SyscallLogPubkey,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
pubkey_addr: u64,
_arg2: u64,
@ -108,10 +108,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Log data handling
SyscallLogData,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
addr: u64,
len: u64,

View File

@ -1,6 +1,5 @@
use {
super::*,
crate::declare_syscall,
solana_rbpf::{error::EbpfError, memory_region::MemoryRegion},
std::slice,
};
@ -14,10 +13,10 @@ fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Erro
consume_compute_meter(invoke_context, cost)
}
declare_syscall!(
declare_builtin_function!(
/// memcpy
SyscallMemcpy,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
dst_addr: u64,
src_addr: u64,
@ -37,10 +36,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// memmove
SyscallMemmove,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
dst_addr: u64,
src_addr: u64,
@ -55,10 +54,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// memcmp
SyscallMemcmp,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
s1_addr: u64,
s2_addr: u64,
@ -113,10 +112,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// memset
SyscallMemset,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
dst_addr: u64,
c: u64,
@ -375,7 +374,6 @@ impl<'a> MemoryChunkIterator<'a> {
len: u64,
) -> Result<MemoryChunkIterator<'a>, EbpfError> {
let vm_addr_end = vm_addr.checked_add(len).ok_or(EbpfError::AccessViolation(
0,
access_type,
vm_addr,
len,
@ -394,26 +392,19 @@ impl<'a> MemoryChunkIterator<'a> {
fn region(&mut self, vm_addr: u64) -> Result<&'a MemoryRegion, Error> {
match self.memory_mapping.region(self.access_type, vm_addr) {
Ok(region) => Ok(region),
Err(error) => match error.downcast_ref() {
Some(EbpfError::AccessViolation(pc, access_type, _vm_addr, _len, name)) => {
Err(Box::new(EbpfError::AccessViolation(
*pc,
*access_type,
self.initial_vm_addr,
self.len,
name,
)))
}
Some(EbpfError::StackAccessViolation(pc, access_type, _vm_addr, _len, frame)) => {
Err(error) => match error {
EbpfError::AccessViolation(access_type, _vm_addr, _len, name) => Err(Box::new(
EbpfError::AccessViolation(access_type, self.initial_vm_addr, self.len, name),
)),
EbpfError::StackAccessViolation(access_type, _vm_addr, _len, frame) => {
Err(Box::new(EbpfError::StackAccessViolation(
*pc,
*access_type,
access_type,
self.initial_vm_addr,
self.len,
*frame,
frame,
)))
}
_ => Err(error),
_ => Err(error.into()),
},
}
}
@ -489,7 +480,7 @@ mod tests {
use {
super::*,
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>(
@ -547,7 +538,7 @@ mod tests {
.unwrap();
assert_matches!(
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,
@ -558,7 +549,7 @@ mod tests {
assert!(src_chunk_iter.next().unwrap().is_ok());
assert_matches!(
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()
@ -568,7 +559,7 @@ mod tests {
.rev();
assert_matches!(
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()
@ -579,7 +570,7 @@ mod tests {
assert!(src_chunk_iter.next().unwrap().is_ok());
assert_matches!(
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,
|_src, _dst, _len| Ok::<_, Error>(0),
).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
@ -722,12 +713,12 @@ mod tests {
false,
|_src, _dst, _len| Ok::<_, Error>(0),
).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]
#[should_panic(expected = "AccessViolation(0, Store, 4294967296, 4")]
#[should_panic(expected = "AccessViolation(Store, 4294967296, 4")]
fn test_memmove_non_contiguous_readonly() {
let config = Config {
aligned_memory_mapping: false,
@ -817,7 +808,7 @@ mod tests {
}
#[test]
#[should_panic(expected = "AccessViolation(0, Store, 4294967296, 9")]
#[should_panic(expected = "AccessViolation(Store, 4294967296, 9")]
fn test_memset_non_contiguous_readonly() {
let config = Config {
aligned_memory_mapping: false,

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
use {super::*, crate::declare_syscall};
use super::*;
fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
sysvar: Result<Arc<T>, InstructionError>,
@ -22,10 +22,10 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
Ok(SUCCESS)
}
declare_syscall!(
declare_builtin_function!(
/// Get a Clock sysvar
SyscallGetClockSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,
@ -44,10 +44,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Get a EpochSchedule sysvar
SyscallGetEpochScheduleSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,
@ -66,10 +66,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Get a EpochRewards sysvar
SyscallGetEpochRewardsSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,
@ -88,10 +88,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Get a Fees sysvar
SyscallGetFeesSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,
@ -113,10 +113,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Get a Rent sysvar
SyscallGetRentSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,
@ -135,10 +135,10 @@ declare_syscall!(
}
);
declare_syscall!(
declare_builtin_function!(
/// Get a Last Restart Slot sysvar
SyscallGetLastRestartSlotSysvar,
fn inner_call(
fn rust(
invoke_context: &mut InvokeContext,
var_addr: u64,
_arg2: u64,

View File

@ -2,11 +2,7 @@ use solana_program_runtime::declare_process_instruction;
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|_invoke_context| {
// Do nothing, compute budget instructions handled by the runtime
Ok(())
}
);
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |_invoke_context| {
// Do nothing, compute budget instructions handled by the runtime
Ok(())
});

View File

@ -13,131 +13,127 @@ use {
pub const DEFAULT_COMPUTE_UNITS: u64 = 450;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data();
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
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 config_account_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?;
let config_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let is_config_account_signer = config_account.is_signer();
let current_data: ConfigKeys = {
if config_account.get_owner() != &crate::id() {
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 key_list: ConfigKeys = limited_deserialize(data)?;
let config_account_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?;
let config_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let is_config_account_signer = config_account.is_signer();
let current_data: ConfigKeys = {
if config_account.get_owner() != &crate::id() {
return Err(InstructionError::InvalidAccountOwner);
}
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 {
deserialize(config_account.get_data()).map_err(|err| {
ic_msg!(
invoke_context,
"too few signers: {:?}; expected: {:?}",
counter,
current_signer_keys.len()
"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 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)]
mod tests {
@ -169,7 +165,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|_invoke_context| {},
|_invoke_context| {},
)

View File

@ -12,10 +12,12 @@ use {
},
solana_rbpf::{
aligned_memory::AlignedMemory,
ebpf,
elf::{Executable, FunctionRegistry},
declare_builtin_function, ebpf,
elf::Executable,
error::ProgramResult,
memory_region::{MemoryMapping, MemoryRegion},
vm::{BuiltinProgram, Config, ContextObject, EbpfVm, ProgramResult},
program::{BuiltinProgram, FunctionRegistry},
vm::{Config, ContextObject, EbpfVm},
},
solana_sdk::{
entrypoint::SUCCESS,
@ -81,7 +83,6 @@ pub fn create_program_runtime_environment_v2<'a>(
reject_broken_elfs: true,
noop_instruction_rate: 256,
sanitize_user_provided_values: true,
encrypt_runtime_environment: true,
external_internal_function_hash_collision: true,
reject_callx_r10: true,
enable_sbpf_v1: false,
@ -131,7 +132,7 @@ pub fn create_vm<'a, 'b>(
Box::new(InstructionError::ProgramEnvironmentSetupFailure)
})?;
Ok(EbpfVm::new(
config,
program.get_loader().clone(),
sbpf_version,
invoke_context,
memory_mapping,
@ -182,9 +183,9 @@ fn execute<'a, 'b: 'a>(
match result {
ProgramResult::Ok(status) if status != SUCCESS => {
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(()),
}
}
@ -527,18 +528,20 @@ pub fn process_instruction_transfer_authority(
Ok(())
}
pub fn process_instruction(
invoke_context: &mut InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut MemoryMapping,
result: &mut ProgramResult,
) {
*result = process_instruction_inner(invoke_context).into();
}
declare_builtin_function!(
Entrypoint,
fn rust(
invoke_context: &mut InvokeContext,
_arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
process_instruction_inner(invoke_context)
}
);
pub fn process_instruction_inner(
invoke_context: &mut InvokeContext,
@ -700,7 +703,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
invoke_context
.programs_modified_by_tx

View File

@ -5341,6 +5341,7 @@ dependencies = [
"solana-runtime",
"solana-sdk",
"solana-vote-program",
"solana_rbpf",
"test-case",
"thiserror",
"tokio",
@ -6514,9 +6515,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.7.2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196"
checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3"
dependencies = [
"byteorder 1.5.0",
"combine",

View File

@ -48,7 +48,7 @@ solana-sdk = { path = "../../sdk", version = "=1.18.0" }
solana-transaction-status = { path = "../../transaction-status", 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_rbpf = "=0.7.2"
solana_rbpf = "=0.8.0"
static_assertions = "1.1.0"
thiserror = "1.0"

View File

@ -1449,7 +1449,7 @@ fn assert_instruction_count() {
transaction_accounts,
instruction_accounts,
Ok(()),
solana_bpf_loader_program::process_instruction,
solana_bpf_loader_program::Entrypoint::vm,
|invoke_context| {
*prev_compute_meter.borrow_mut() = invoke_context.get_remaining();
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();
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 instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -4428,7 +4428,7 @@ fn test_cpi_change_account_data_memory_allocation() {
bank.add_builtin(
builtin_program_id,
"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);

View File

@ -54,411 +54,391 @@ fn get_optional_pubkey<'a>(
pub const DEFAULT_COMPUTE_UNITS: u64 = 750;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data();
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
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 me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if *me.get_owner() != id() {
return Err(InstructionError::InvalidAccountOwner);
let get_stake_account = || {
let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if *me.get_owner() != id() {
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 =
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()?;
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(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);
}
}
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)?;
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,
&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,
)
}
authorize(
&mut me,
&signers,
authorized_pubkey,
stake_authorize,
true,
&clock,
custodian_pubkey,
)
} else {
Err(InstructionError::InvalidInstructionData)
}
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)?;
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(4)?;
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(5)?;
drop(me);
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,
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
.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)?;
.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)?;
}
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 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(
redelegate(
invoke_context,
transaction_context,
instruction_context,
&mut me,
1,
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)]
mod tests {
@ -572,7 +552,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
invoke_context.feature_set = Arc::clone(&feature_set);
},
@ -7046,7 +7026,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
Ok(()),
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
invoke_context.feature_set = Arc::clone(&feature_set);
},

View File

@ -314,252 +314,246 @@ fn transfer_with_seed(
pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let instruction = limited_deserialize(instruction_data)?;
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
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)?;
match instruction {
SystemInstruction::CreateAccount {
let signers = instruction_context.get_signers(transaction_context)?;
match instruction {
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,
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,
space,
&owner,
&signers,
invoke_context,
transaction_context,
instruction_context,
)
}
SystemInstruction::CreateAccountWithSeed {
base,
seed,
&owner,
&signers,
invoke_context,
transaction_context,
instruction_context,
)
}
SystemInstruction::CreateAccountWithSeed {
base,
seed,
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)?,
)?,
Some((&base, &seed, &owner)),
invoke_context,
)?;
create_account(
0,
1,
&to_address,
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)?,
)?,
Some((&base, &seed, &owner)),
invoke_context,
)?;
create_account(
0,
1,
&to_address,
lamports,
space,
&owner,
&signers,
invoke_context,
transaction_context,
instruction_context,
)
}
SystemInstruction::Assign { 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)?,
)?,
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 {
&owner,
&signers,
invoke_context,
transaction_context,
instruction_context,
)
}
SystemInstruction::Assign { 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)?,
)?,
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,
from_seed,
from_owner,
} => {
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::TransferWithSeed {
lamports,
from_seed,
from_owner,
} => {
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,
transaction_context,
instruction_context,
)
"Advance nonce account: recent blockhash list is empty",
);
return Err(SystemError::NonceNoRecentBlockhashes.into());
}
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(
advance_nonce_account(&mut me, &signers, invoke_context)
}
SystemInstruction::WithdrawNonceAccount(lamports) => {
instruction_context.check_number_of_instruction_accounts(2)?;
#[allow(deprecated)]
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,
instruction_context,
1,
)?;
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)
"Initialize nonce account: recent blockhash list is empty",
);
return Err(SystemError::NonceNoRecentBlockhashes.into());
}
SystemInstruction::WithdrawNonceAccount(lamports) => {
instruction_context.check_number_of_instruction_accounts(2)?;
#[allow(deprecated)]
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,
)
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) => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut me =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
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);
}
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,
"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)
if !nonce_account.is_writable() {
return Err(InstructionError::InvalidArgument);
}
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut me =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
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)
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)
}
}
);
});
#[cfg(test)]
mod tests {
@ -609,7 +603,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|_invoke_context| {},
|_invoke_context| {},
)
@ -1599,7 +1593,7 @@ mod tests {
},
],
Ok(()),
super::process_instruction,
Entrypoint::vm,
|invoke_context: &mut InvokeContext| {
invoke_context.blockhash = hash(&serialize(&0).unwrap());
},
@ -1946,7 +1940,7 @@ mod tests {
},
],
Err(SystemError::NonceNoRecentBlockhashes.into()),
super::process_instruction,
Entrypoint::vm,
|invoke_context: &mut InvokeContext| {
invoke_context.blockhash = hash(&serialize(&0).unwrap());
},

View File

@ -108,7 +108,7 @@ fn bench_process_vote_instruction(
transaction_accounts.clone(),
instruction_account_metas.clone(),
Ok(()),
solana_vote_program::vote_processor::process_instruction,
solana_vote_program::vote_processor::Entrypoint::vm,
|_invoke_context| {},
|_invoke_context| {},
);

View File

@ -54,209 +54,198 @@ fn process_authorize_with_seed_instruction(
// units; can consume based on instructions in the future like `bpf_loader` does.
pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100;
declare_process_instruction!(
process_instruction,
DEFAULT_COMPUTE_UNITS,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data();
declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
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)?;
if *me.get_owner() != id() {
return Err(InstructionError::InvalidAccountOwner);
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if *me.get_owner() != id() {
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)?;
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) => {
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 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)?,
)?;
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(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
vote_state::authorize(
&mut me,
&slot_hashes,
voter_pubkey,
vote_authorize,
&signers,
&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,
)
}
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)
}
} else {
Err(InstructionError::InvalidInstructionData)
}
}
}
);
});
#[cfg(test)]
mod tests {
@ -320,7 +309,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|_invoke_context| {},
|_invoke_context| {},
)
@ -339,7 +328,7 @@ mod tests {
transaction_accounts,
instruction_accounts,
expected_result,
super::process_instruction,
Entrypoint::vm,
|invoke_context| {
invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default());
},

View File

@ -130,7 +130,7 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(),
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
let native_programs_consume_cu = invoke_context
.feature_set

View File

@ -125,13 +125,13 @@ fn do_bench_transactions(
// freeze bank so that slot hashes is populated
bank.freeze();
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
declare_process_instruction!(MockBuiltin, 1, |_invoke_context| {
// Do nothing
Ok(())
});
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);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(bank.clone());

View File

@ -107,7 +107,7 @@ use {
solana_program_runtime::{
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
compute_budget::{self, ComputeBudget},
invoke_context::ProcessInstructionWithContext,
invoke_context::BuiltinFunctionWithContext,
loaded_programs::{
LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET,
@ -7885,12 +7885,12 @@ impl Bank {
pub fn add_mockup_builtin(
&mut self,
program_id: Pubkey,
entrypoint: ProcessInstructionWithContext,
builtin_function: BuiltinFunctionWithContext,
) {
self.add_builtin(
program_id,
"mockup".to_string(),
LoadedProgram::new_builtin(self.slot, 0, entrypoint),
LoadedProgram::new_builtin(self.slot, 0, builtin_function),
);
}

View File

@ -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
Ok(())
});
@ -1246,7 +1246,7 @@ fn test_rent_complex() {
Deduction,
}
declare_process_instruction!(process_instruction, 1, |invoke_context| {
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
@ -1281,7 +1281,7 @@ fn test_rent_complex() {
root_bank.restore_old_behavior_for_fragile_tests();
let root_bank = Arc::new(root_bank);
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());
@ -4684,7 +4684,7 @@ fn test_add_builtin() {
fn mock_vote_program_id() -> Pubkey {
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 instruction_context = transaction_context.get_current_instruction_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());
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());
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);
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))
});
@ -4771,7 +4771,7 @@ fn test_add_duplicate_static_program() {
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();
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();
// 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());
@ -4789,7 +4789,7 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
for pass in 0..5 {
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))
});
@ -4825,12 +4825,12 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
bank.add_builtin(
vote_id,
"mock_program1".to_string(),
LoadedProgram::new_builtin(0, 0, process_instruction),
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
);
bank.add_builtin(
stake_id,
"mock_program2".to_string(),
LoadedProgram::new_builtin(0, 0, process_instruction),
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
);
{
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
bank.update_accounts_hash_for_tests();
let old_hash = bank.get_accounts_hash().unwrap();
bank.add_mockup_builtin(vote_id, process_instruction);
bank.add_mockup_builtin(stake_id, process_instruction);
bank.add_mockup_builtin(vote_id, MockBuiltin::vm);
bank.add_mockup_builtin(stake_id, MockBuiltin::vm);
add_root_and_flush_write_cache(&bank);
bank.update_accounts_hash_for_tests();
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 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 instruction_context = transaction_context.get_current_instruction_context()?;
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]);
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 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 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 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 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);
assert_eq!(result, Ok(()));
let account = bank.get_account(&solana_vote_program::id()).unwrap();
@ -6248,7 +6248,7 @@ fn test_duplicate_account_key() {
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 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),
];
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 mut tx = Transaction::new_signed_with_payer(
@ -6310,7 +6310,7 @@ fn test_program_id_as_payer() {
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 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 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 mut tx = Transaction::new_signed_with_payer(
@ -6390,7 +6390,7 @@ fn test_fuzz_instructions() {
bank.add_builtin(
key,
name.clone(),
LoadedProgram::new_builtin(0, 0, process_instruction),
LoadedProgram::new_builtin(0, 0, MockBuiltin::vm),
);
(key, name.as_bytes().to_vec())
})
@ -6584,7 +6584,7 @@ fn test_bank_hash_consistency() {
#[ignore]
#[test]
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 instruction_context = transaction_context.get_current_instruction_context()?;
instruction_context
@ -6597,7 +6597,7 @@ fn test_same_program_id_uses_unique_executable_accounts() {
// Add a new program
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
let program2_pubkey = solana_sdk::pubkey::new_rand();
@ -6814,13 +6814,13 @@ fn test_add_builtin_no_overwrite() {
Arc::get_mut(&mut bank)
.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);
let mut bank = Arc::new(new_from_parent(bank));
Arc::get_mut(&mut bank)
.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);
}
@ -6838,13 +6838,13 @@ fn test_add_builtin_loader_no_overwrite() {
Arc::get_mut(&mut bank)
.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);
let mut bank = Arc::new(new_from_parent(bank));
Arc::get_mut(&mut bank)
.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);
}
@ -7403,7 +7403,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
],
Vec::new(),
Ok(()),
solana_bpf_loader_program::process_instruction,
solana_bpf_loader_program::Entrypoint::vm,
|invoke_context| {
invoke_context
.programs_modified_by_tx
@ -9708,7 +9708,7 @@ fn test_tx_return_data() {
);
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 transaction_context = &mut invoke_context.transaction_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 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 [
None,
@ -9906,7 +9906,7 @@ fn test_transfer_sysvar() {
);
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 instruction_context = transaction_context.get_current_instruction_context()?;
instruction_context
@ -9916,7 +9916,7 @@ fn test_transfer_sysvar() {
});
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();
#[allow(deprecated)]
@ -10115,7 +10115,7 @@ fn test_compute_budget_program_noop() {
);
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();
assert_eq!(
*compute_budget,
@ -10128,7 +10128,7 @@ fn test_compute_budget_program_noop() {
Ok(())
});
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(
&[
@ -10158,7 +10158,7 @@ fn test_compute_request_instruction() {
);
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();
assert_eq!(
*compute_budget,
@ -10171,7 +10171,7 @@ fn test_compute_request_instruction() {
Ok(())
});
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(
&[
@ -10208,7 +10208,7 @@ fn test_failed_compute_request_instruction() {
bank.transfer(10, &mint_keypair, &payer1_keypair.pubkey())
.unwrap();
declare_process_instruction!(process_instruction, 1, |invoke_context| {
declare_process_instruction!(MockBuiltin, 1, |invoke_context| {
let compute_budget = invoke_context.get_compute_budget();
assert_eq!(
*compute_budget,
@ -10221,7 +10221,7 @@ fn test_failed_compute_request_instruction() {
Ok(())
});
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
let message0 = Message::new(
@ -10825,7 +10825,7 @@ enum MockTransferInstruction {
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 instruction_context = transaction_context.get_current_instruction_context()?;
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);
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 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 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 check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
@ -11050,7 +11050,7 @@ fn test_drained_created_account() {
let created_keypair = Keypair::new();
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();
// Create and drain a small data size account
@ -11578,7 +11578,7 @@ enum MockReallocInstruction {
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 instruction_context = transaction_context.get_current_instruction_context()?;
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 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 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);
let mut bank = Bank::new_for_tests(&genesis_config);
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();

View File

@ -1,5 +1,5 @@
use {
solana_program_runtime::invoke_context::ProcessInstructionWithContext,
solana_program_runtime::invoke_context::BuiltinFunctionWithContext,
solana_sdk::{
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 program_id: Pubkey,
pub name: &'static str,
pub entrypoint: ProcessInstructionWithContext,
pub entrypoint: BuiltinFunctionWithContext,
}
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 {
fn example() -> Self {
// 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
Ok(())
});
@ -35,7 +35,7 @@ impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
feature_id: None,
program_id: Pubkey::default(),
name: "",
entrypoint,
entrypoint: MockBuiltin::vm,
}
}
}
@ -45,66 +45,66 @@ pub static BUILTINS: &[BuiltinPrototype] = &[
feature_id: None,
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::process_instruction,
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_vote_program::id(),
name: "vote_program",
entrypoint: solana_vote_program::vote_processor::process_instruction,
entrypoint: solana_vote_program::vote_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_stake_program::id(),
name: "stake_program",
entrypoint: solana_stake_program::stake_instruction::process_instruction,
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_config_program::id(),
name: "config_program",
entrypoint: solana_config_program::config_processor::process_instruction,
entrypoint: solana_config_program::config_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader_deprecated::id(),
name: "solana_bpf_loader_deprecated_program",
entrypoint: solana_bpf_loader_program::process_instruction,
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader::id(),
name: "solana_bpf_loader_program",
entrypoint: solana_bpf_loader_program::process_instruction,
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader_upgradeable::id(),
name: "solana_bpf_loader_upgradeable_program",
entrypoint: solana_bpf_loader_program::process_instruction,
entrypoint: solana_bpf_loader_program::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_sdk::compute_budget::id(),
name: "compute_budget_program",
entrypoint: solana_compute_budget_program::process_instruction,
entrypoint: solana_compute_budget_program::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_sdk::address_lookup_table::program::id(),
name: "address_lookup_table_program",
entrypoint: solana_address_lookup_table_program::processor::process_instruction,
entrypoint: solana_address_lookup_table_program::processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(feature_set::zk_token_sdk_enabled::id()),
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
name: "zk_token_proof_program",
entrypoint: solana_zk_token_proof_program::process_instruction,
entrypoint: solana_zk_token_proof_program::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()),
program_id: solana_sdk::loader_v4::id(),
name: "loader_v4",
entrypoint: solana_loader_v4_program::process_instruction,
entrypoint: solana_loader_v4_program::Entrypoint::vm,
},
];