Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ siphasher = "0.3.11"
smpl_jwt = "0.7.1"
socket2 = "0.5.4"
soketto = "0.7"
solana_rbpf = "=0.7.2"
solana_rbpf = "=0.8.0"
solana-account-decoder = { path = "account-decoder", version = "=1.17.4" }
solana-accounts-db = { path = "accounts-db", version = "=1.17.4" }
solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.17.4" }
Expand Down
8 changes: 4 additions & 4 deletions ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2989,15 +2989,15 @@ pub mod tests {
]
}

declare_process_instruction!(mock_processor_ok, 1, |_invoke_context| {
declare_process_instruction!(MockBuiltinOk, 1, |_invoke_context| {
// Always succeeds
Ok(())
});

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(
Expand All @@ -3018,7 +3018,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
Expand All @@ -3038,7 +3038,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(
Expand Down
125 changes: 69 additions & 56 deletions program-runtime/src/invoke_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,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, ReadableAccount},
Expand Down Expand Up @@ -44,44 +45,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();
}
);
};
}

Expand Down Expand Up @@ -746,11 +749,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)?;
Expand All @@ -762,31 +765,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)
}
}
Expand Down Expand Up @@ -979,7 +992,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> {
Expand Down Expand Up @@ -1014,7 +1027,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);
Expand Down Expand Up @@ -1062,7 +1075,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;
Expand Down Expand Up @@ -1268,7 +1281,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;

Expand Down Expand Up @@ -1414,7 +1427,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;

Expand Down
13 changes: 7 additions & 6 deletions program-runtime/src/loaded_programs.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use {
crate::{
invoke_context::{InvokeContext, ProcessInstructionWithContext},
invoke_context::{BuiltinFunctionWithContext, InvokeContext},
timings::ExecuteDetailsTimings,
},
itertools::Itertools,
log::{debug, log_enabled, trace},
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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -928,7 +929,7 @@ mod tests {
},
assert_matches::assert_matches,
percentage::Percentage,
solana_rbpf::vm::BuiltinProgram,
solana_rbpf::program::BuiltinProgram,
solana_sdk::{
clock::{Epoch, Slot},
pubkey::Pubkey,
Expand Down
12 changes: 6 additions & 6 deletions program-runtime/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,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();
Expand Down Expand Up @@ -274,7 +274,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| {
Expand Down Expand Up @@ -438,7 +438,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();
Expand Down Expand Up @@ -507,7 +507,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(
Expand Down Expand Up @@ -655,7 +655,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))
});

Expand Down Expand Up @@ -695,7 +695,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();
Expand Down
4 changes: 2 additions & 2 deletions program-runtime/src/stable_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions program-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
Loading