Bump solana_rbpf to 0.2.34 (#28198)

* Bumps solana_rbpf to 0.2.34

* Removes generic UserError from EbpfError.

* Uses ProgramResult for syscalls.
Removes use sites of the question_mark! macro by wrapping the call method of SyscallObjects.

* Uses InvokeContext as syscall context object directly.

* Replaces bind_syscall_context_object() by a parameter in the constructor.

* Inlines bind_syscall_context_objects() at its only call site.
This commit is contained in:
Alexander Meißner 2022-10-06 20:31:58 +02:00 committed by GitHub
parent 66cd290d04
commit 30b0a13ba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1339 additions and 1806 deletions

4
Cargo.lock generated
View File

@ -6806,9 +6806,9 @@ dependencies = [
[[package]] [[package]]
name = "solana_rbpf" name = "solana_rbpf"
version = "0.2.33" version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b13ec17b58709d07634895dbca4cae6bebeaddf3b83bf4fa8dfeaf3621222347" checksum = "334bb11faee82f0306e39944cb4ac85824b7d261f3d99d1f2f8bd09851644f0b"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"combine", "combine",

View File

@ -54,7 +54,7 @@ solana-tpu-client = { path = "../tpu-client", version = "=1.15.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.15.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.15.0" }
solana-version = { path = "../version", version = "=1.15.0" } solana-version = { path = "../version", version = "=1.15.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.15.0" } solana-vote-program = { path = "../programs/vote", version = "=1.15.0" }
solana_rbpf = "=0.2.33" solana_rbpf = "=0.2.34"
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] } spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
thiserror = "1.0.31" thiserror = "1.0.31"
tiny-bip39 = "0.8.2" tiny-bip39 = "0.8.2"

View File

@ -10,7 +10,7 @@ use {
clap::{App, AppSettings, Arg, ArgMatches, SubCommand}, clap::{App, AppSettings, Arg, ArgMatches, SubCommand},
log::*, log::*,
solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig}, solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig},
solana_bpf_loader_program::{syscalls::register_syscalls, BpfError, ThisInstructionMeter}, solana_bpf_loader_program::{syscalls::register_syscalls, ThisInstructionMeter},
solana_clap_utils::{self, input_parsers::*, input_validators::*, keypair::*}, solana_clap_utils::{self, input_parsers::*, input_validators::*, keypair::*},
solana_cli_output::{ solana_cli_output::{
CliProgram, CliProgramAccountType, CliProgramAuthority, CliProgramBuffer, CliProgramId, CliProgram, CliProgramAccountType, CliProgramAuthority, CliProgramBuffer, CliProgramId,
@ -2086,7 +2086,7 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
// Verify the program // Verify the program
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
&program_data, &program_data,
Config { Config {
reject_broken_elfs: true, reject_broken_elfs: true,
@ -2097,9 +2097,7 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
.map_err(|err| format!("ELF error: {}", err))?; .map_err(|err| format!("ELF error: {}", err))?;
let _ = let _ =
VerifiedExecutable::<RequisiteVerifier, BpfError, ThisInstructionMeter>::from_executable( VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(executable)
executable,
)
.map_err(|err| format!("ELF error: {}", err))?; .map_err(|err| format!("ELF error: {}", err))?;
Ok(program_data) Ok(program_data)

View File

@ -6000,9 +6000,9 @@ dependencies = [
[[package]] [[package]]
name = "solana_rbpf" name = "solana_rbpf"
version = "0.2.33" version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b13ec17b58709d07634895dbca4cae6bebeaddf3b83bf4fa8dfeaf3621222347" checksum = "334bb11faee82f0306e39944cb4ac85824b7d261f3d99d1f2f8bd09851644f0b"
dependencies = [ dependencies = [
"byteorder 1.4.3", "byteorder 1.4.3",
"combine", "combine",

View File

@ -38,7 +38,7 @@ solana-program-runtime = { path = "../../program-runtime", version = "=1.15.0" }
solana-runtime = { path = "../../runtime", version = "=1.15.0" } solana-runtime = { path = "../../runtime", version = "=1.15.0" }
solana-sdk = { path = "../../sdk", version = "=1.15.0" } solana-sdk = { path = "../../sdk", version = "=1.15.0" }
solana-transaction-status = { path = "../../transaction-status", version = "=1.15.0" } solana-transaction-status = { path = "../../transaction-status", version = "=1.15.0" }
solana_rbpf = "=0.2.33" solana_rbpf = "=0.2.34"
[dev-dependencies] [dev-dependencies]
solana-ledger = { path = "../../ledger", version = "=1.15.0" } solana-ledger = { path = "../../ledger", version = "=1.15.0" }

View File

@ -8,7 +8,7 @@ extern crate solana_bpf_loader_program;
use { use {
byteorder::{ByteOrder, LittleEndian, WriteBytesExt}, byteorder::{ByteOrder, LittleEndian, WriteBytesExt},
solana_bpf_loader_program::{ solana_bpf_loader_program::{
create_vm, serialization::serialize_parameters, syscalls::register_syscalls, BpfError, create_vm, serialization::serialize_parameters, syscalls::register_syscalls,
ThisInstructionMeter, ThisInstructionMeter,
}, },
solana_measure::measure::Measure, solana_measure::measure::Measure,
@ -81,7 +81,7 @@ fn bench_program_create_executable(bencher: &mut Bencher) {
let elf = load_elf("bench_alu").unwrap(); let elf = load_elf("bench_alu").unwrap();
bencher.iter(|| { bencher.iter(|| {
let _ = Executable::<BpfError, ThisInstructionMeter>::from_elf( let _ = Executable::<ThisInstructionMeter>::from_elf(
&elf, &elf,
Config::default(), Config::default(),
SyscallRegistry::default(), SyscallRegistry::default(),
@ -106,18 +106,17 @@ fn bench_program_alu(bencher: &mut Bencher) {
.get_compute_meter() .get_compute_meter()
.borrow_mut() .borrow_mut()
.mock_set_remaining(std::i64::MAX as u64); .mock_set_remaining(std::i64::MAX as u64);
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
&elf, &elf,
Config::default(), Config::default(),
register_syscalls(invoke_context, true).unwrap(), register_syscalls(invoke_context, true).unwrap(),
) )
.unwrap(); .unwrap();
let mut verified_executable = VerifiedExecutable::< let mut verified_executable =
RequisiteVerifier, VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(
BpfError, executable,
ThisInstructionMeter, )
>::from_executable(executable)
.unwrap(); .unwrap();
verified_executable.jit_compile().unwrap(); verified_executable.jit_compile().unwrap();
@ -235,18 +234,17 @@ fn bench_create_vm(bencher: &mut Bencher) {
) )
.unwrap(); .unwrap();
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
&elf, &elf,
Config::default(), Config::default(),
register_syscalls(invoke_context, true).unwrap(), register_syscalls(invoke_context, true).unwrap(),
) )
.unwrap(); .unwrap();
let verified_executable = VerifiedExecutable::< let verified_executable =
RequisiteVerifier, VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(
BpfError, executable,
ThisInstructionMeter, )
>::from_executable(executable)
.unwrap(); .unwrap();
bencher.iter(|| { bencher.iter(|| {
@ -283,18 +281,17 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
) )
.unwrap(); .unwrap();
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
&elf, &elf,
Config::default(), Config::default(),
register_syscalls(invoke_context, true).unwrap(), register_syscalls(invoke_context, true).unwrap(),
) )
.unwrap(); .unwrap();
let verified_executable = VerifiedExecutable::< let verified_executable =
RequisiteVerifier, VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(
BpfError, executable,
ThisInstructionMeter, )
>::from_executable(executable)
.unwrap(); .unwrap();
let compute_meter = invoke_context.get_compute_meter(); let compute_meter = invoke_context.get_compute_meter();

View File

@ -55,7 +55,7 @@ use {
create_vm, create_vm,
serialization::{deserialize_parameters, serialize_parameters}, serialization::{deserialize_parameters, serialize_parameters},
syscalls::register_syscalls, syscalls::register_syscalls,
BpfError, ThisInstructionMeter, ThisInstructionMeter,
}, },
solana_program_runtime::invoke_context::with_mock_invoke_context, solana_program_runtime::invoke_context::with_mock_invoke_context,
solana_rbpf::{ solana_rbpf::{
@ -241,7 +241,7 @@ fn run_program(name: &str) -> u64 {
reject_broken_elfs: true, reject_broken_elfs: true,
..Config::default() ..Config::default()
}; };
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
&data, &data,
config, config,
register_syscalls(invoke_context, true /* no sol_alloc_free */).unwrap(), register_syscalls(invoke_context, true /* no sol_alloc_free */).unwrap(),
@ -249,11 +249,10 @@ fn run_program(name: &str) -> u64 {
.unwrap(); .unwrap();
#[allow(unused_mut)] #[allow(unused_mut)]
let mut verified_executable = VerifiedExecutable::< let mut verified_executable =
RequisiteVerifier, VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(
BpfError, executable,
ThisInstructionMeter, )
>::from_executable(executable)
.unwrap(); .unwrap();
let run_program_iterations = { let run_program_iterations = {
@ -300,7 +299,10 @@ fn run_program(name: &str) -> u64 {
instruction_count = vm.get_total_instruction_count(); instruction_count = vm.get_total_instruction_count();
if config.enable_instruction_tracing { if config.enable_instruction_tracing {
if i == 1 { if i == 1 {
if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) { if !Tracer::compare(
tracer.as_ref().unwrap(),
&vm.get_program_environment().tracer,
) {
let analysis = let analysis =
Analysis::from_executable(verified_executable.get_executable()) Analysis::from_executable(verified_executable.get_executable())
.unwrap(); .unwrap();
@ -312,7 +314,8 @@ fn run_program(name: &str) -> u64 {
.write(&mut stdout.lock(), &analysis) .write(&mut stdout.lock(), &analysis)
.unwrap(); .unwrap();
println!("TRACE (jit):"); println!("TRACE (jit):");
vm.get_tracer() vm.get_program_environment()
.tracer
.write(&mut stdout.lock(), &analysis) .write(&mut stdout.lock(), &analysis)
.unwrap(); .unwrap();
assert!(false); assert!(false);
@ -330,7 +333,7 @@ fn run_program(name: &str) -> u64 {
trace!("BPF Program Instruction Trace:\n{}", trace_string); trace!("BPF Program Instruction Trace:\n{}", trace_string);
} }
} }
tracer = Some(vm.get_tracer().clone()); tracer = Some(vm.get_program_environment().tracer.clone());
} }
} }
assert!(match deserialize_parameters( assert!(match deserialize_parameters(

View File

@ -19,7 +19,7 @@ solana-metrics = { path = "../../metrics", version = "=1.15.0" }
solana-program-runtime = { path = "../../program-runtime", version = "=1.15.0" } solana-program-runtime = { path = "../../program-runtime", version = "=1.15.0" }
solana-sdk = { path = "../../sdk", version = "=1.15.0" } solana-sdk = { path = "../../sdk", version = "=1.15.0" }
solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.15.0" } solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.15.0" }
solana_rbpf = "=0.2.33" solana_rbpf = "=0.2.34"
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies] [dev-dependencies]

View File

@ -14,6 +14,7 @@ extern crate solana_metrics;
use { use {
crate::{ crate::{
allocator_bump::BpfAllocator,
serialization::{deserialize_parameters, serialize_parameters}, serialization::{deserialize_parameters, serialize_parameters},
syscalls::SyscallError, syscalls::SyscallError,
}, },
@ -28,13 +29,13 @@ use {
}, },
solana_rbpf::{ solana_rbpf::{
aligned_memory::AlignedMemory, aligned_memory::AlignedMemory,
ebpf::{HOST_ALIGN, MM_INPUT_START}, ebpf::{HOST_ALIGN, MM_HEAP_START, MM_INPUT_START},
elf::Executable, elf::Executable,
error::{EbpfError, UserDefinedError}, error::{EbpfError, UserDefinedError},
memory_region::MemoryRegion, memory_region::MemoryRegion,
static_analysis::Analysis, static_analysis::Analysis,
verifier::{RequisiteVerifier, VerifierError}, verifier::{RequisiteVerifier, VerifierError},
vm::{Config, EbpfVm, InstructionMeter, VerifiedExecutable}, vm::{Config, EbpfVm, InstructionMeter, ProgramResult, VerifiedExecutable},
}, },
solana_sdk::{ solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
@ -42,9 +43,10 @@ use {
entrypoint::{HEAP_LENGTH, SUCCESS}, entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::{ feature_set::{
cap_accounts_data_allocations_per_transaction, cap_bpf_program_instruction_accounts, cap_accounts_data_allocations_per_transaction, cap_bpf_program_instruction_accounts,
disable_deploy_of_alloc_free_syscall, disable_deprecated_loader, check_slice_translation_size, disable_deploy_of_alloc_free_syscall,
enable_bpf_loader_extend_program_ix, error_on_syscall_bpf_function_hash_collisions, disable_deprecated_loader, enable_bpf_loader_extend_program_ix,
limit_max_instruction_trace_length, reject_callx_r10, error_on_syscall_bpf_function_hash_collisions, limit_max_instruction_trace_length,
reject_callx_r10,
}, },
instruction::{AccountMeta, InstructionError}, instruction::{AccountMeta, InstructionError},
loader_instruction::LoaderInstruction, loader_instruction::LoaderInstruction,
@ -80,7 +82,7 @@ pub enum BpfError {
} }
impl UserDefinedError for BpfError {} impl UserDefinedError for BpfError {}
fn map_ebpf_error(invoke_context: &InvokeContext, e: EbpfError<BpfError>) -> InstructionError { fn map_ebpf_error(invoke_context: &InvokeContext, e: EbpfError) -> InstructionError {
ic_msg!(invoke_context, "{}", e); ic_msg!(invoke_context, "{}", e);
InstructionError::InvalidAccountData InstructionError::InvalidAccountData
} }
@ -201,7 +203,7 @@ pub fn create_executor(
)?; )?;
create_executor_metrics.program_id = programdata.get_key().to_string(); create_executor_metrics.program_id = programdata.get_key().to_string();
let mut load_elf_time = Measure::start("load_elf_time"); let mut load_elf_time = Measure::start("load_elf_time");
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf( let executable = Executable::<ThisInstructionMeter>::from_elf(
programdata programdata
.get_data() .get_data()
.get(programdata_offset..) .get(programdata_offset..)
@ -220,9 +222,7 @@ pub fn create_executor(
.map_err(|e| map_ebpf_error(invoke_context, e))?; .map_err(|e| map_ebpf_error(invoke_context, e))?;
let mut verify_code_time = Measure::start("verify_code_time"); let mut verify_code_time = Measure::start("verify_code_time");
let mut verified_executable = let mut verified_executable =
VerifiedExecutable::<RequisiteVerifier, BpfError, ThisInstructionMeter>::from_executable( VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(executable)
executable,
)
.map_err(|e| map_ebpf_error(invoke_context, e))?; .map_err(|e| map_ebpf_error(invoke_context, e))?;
verify_code_time.stop(); verify_code_time.stop();
create_executor_metrics.verify_code_us = verify_code_time.as_us(); create_executor_metrics.verify_code_us = verify_code_time.as_us();
@ -289,11 +289,11 @@ fn check_loader_id(id: &Pubkey) -> bool {
/// Create the BPF virtual machine /// Create the BPF virtual machine
pub fn create_vm<'a, 'b>( pub fn create_vm<'a, 'b>(
program: &'a VerifiedExecutable<RequisiteVerifier, BpfError, ThisInstructionMeter>, program: &'a VerifiedExecutable<RequisiteVerifier, ThisInstructionMeter>,
parameter_bytes: &mut [u8], parameter_bytes: &mut [u8],
orig_account_lengths: Vec<usize>, orig_account_lengths: Vec<usize>,
invoke_context: &'a mut InvokeContext<'b>, invoke_context: &'a mut InvokeContext<'b>,
) -> Result<EbpfVm<'a, RequisiteVerifier, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> { ) -> Result<EbpfVm<'a, RequisiteVerifier, ThisInstructionMeter>, EbpfError> {
let compute_budget = invoke_context.get_compute_budget(); let compute_budget = invoke_context.get_compute_budget();
let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH); let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH);
let _ = invoke_context.get_compute_meter().borrow_mut().consume( let _ = invoke_context.get_compute_meter().borrow_mut().consume(
@ -304,8 +304,33 @@ pub fn create_vm<'a, 'b>(
let mut heap = let mut heap =
AlignedMemory::<HOST_ALIGN>::zero_filled(compute_budget.heap_size.unwrap_or(HEAP_LENGTH)); AlignedMemory::<HOST_ALIGN>::zero_filled(compute_budget.heap_size.unwrap_or(HEAP_LENGTH));
let parameter_region = MemoryRegion::new_writable(parameter_bytes, MM_INPUT_START); let parameter_region = MemoryRegion::new_writable(parameter_bytes, MM_INPUT_START);
let mut vm = EbpfVm::new(program, heap.as_slice_mut(), vec![parameter_region])?; let vm = EbpfVm::new(
syscalls::bind_syscall_context_objects(&mut vm, invoke_context, heap, orig_account_lengths)?; program,
invoke_context,
heap.as_slice_mut(),
vec![parameter_region],
)?;
let check_aligned = bpf_loader_deprecated::id()
!= invoke_context
.transaction_context
.get_current_instruction_context()
.and_then(|instruction_context| {
instruction_context
.try_borrow_last_program_account(invoke_context.transaction_context)
})
.map(|program_account| *program_account.get_owner())
.map_err(SyscallError::InstructionError)?;
let check_size = invoke_context
.feature_set
.is_active(&check_slice_translation_size::id());
invoke_context
.set_syscall_context(
check_aligned,
check_size,
orig_account_lengths,
Rc::new(RefCell::new(BpfAllocator::new(heap, MM_HEAP_START))),
)
.map_err(SyscallError::InstructionError)?;
Ok(vm) Ok(vm)
} }
@ -1281,7 +1306,7 @@ impl InstructionMeter for ThisInstructionMeter {
/// BPF Loader's Executor implementation /// BPF Loader's Executor implementation
pub struct BpfExecutor { pub struct BpfExecutor {
verified_executable: VerifiedExecutable<RequisiteVerifier, BpfError, ThisInstructionMeter>, verified_executable: VerifiedExecutable<RequisiteVerifier, ThisInstructionMeter>,
use_jit: bool, use_jit: bool,
} }
@ -1353,7 +1378,10 @@ impl Executor for BpfExecutor {
let mut trace_buffer = Vec::<u8>::new(); let mut trace_buffer = Vec::<u8>::new();
let analysis = let analysis =
Analysis::from_executable(self.verified_executable.get_executable()).unwrap(); Analysis::from_executable(self.verified_executable.get_executable()).unwrap();
vm.get_tracer().write(&mut trace_buffer, &analysis).unwrap(); vm.get_program_environment()
.tracer
.write(&mut trace_buffer, &analysis)
.unwrap();
let trace_string = String::from_utf8(trace_buffer).unwrap(); let trace_string = String::from_utf8(trace_buffer).unwrap();
trace!("BPF Program Instruction Trace:\n{}", trace_string); trace!("BPF Program Instruction Trace:\n{}", trace_string);
} }
@ -1364,7 +1392,7 @@ impl Executor for BpfExecutor {
stable_log::program_return(&log_collector, &program_id, return_data); stable_log::program_return(&log_collector, &program_id, return_data);
} }
match result { match result {
Ok(status) if status != SUCCESS => { ProgramResult::Ok(status) if status != SUCCESS => {
let error: InstructionError = if (status let error: InstructionError = if (status
== MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED == MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED
&& !invoke_context && !invoke_context
@ -1386,11 +1414,24 @@ impl Executor for BpfExecutor {
stable_log::program_failure(&log_collector, &program_id, &error); stable_log::program_failure(&log_collector, &program_id, &error);
Err(error) Err(error)
} }
Err(error) => { ProgramResult::Err(error) => {
let error = match error { let error = match error {
EbpfError::UserError(BpfError::SyscallError( /*EbpfError::UserError(user_error) if let BpfError::SyscallError(
SyscallError::InstructionError(error), SyscallError::InstructionError(instruction_error),
)) => error, ) = user_error.downcast_ref::<BpfError>().unwrap() => instruction_error.clone(),*/
EbpfError::UserError(user_error)
if matches!(
user_error.downcast_ref::<BpfError>().unwrap(),
BpfError::SyscallError(SyscallError::InstructionError(_)),
) =>
{
match user_error.downcast_ref::<BpfError>().unwrap() {
BpfError::SyscallError(SyscallError::InstructionError(
instruction_error,
)) => instruction_error.clone(),
_ => unreachable!(),
}
}
err => { err => {
ic_logger_msg!(log_collector, "Program failed to complete: {}", err); ic_logger_msg!(log_collector, "Program failed to complete: {}", err);
InstructionError::ProgramFailedToComplete InstructionError::ProgramFailedToComplete
@ -1536,21 +1577,21 @@ mod tests {
"entrypoint", "entrypoint",
) )
.unwrap(); .unwrap();
let executable = Executable::<BpfError, TestInstructionMeter>::from_text_bytes( let executable = Executable::<TestInstructionMeter>::from_text_bytes(
program, program,
config, config,
syscall_registry, syscall_registry,
bpf_functions, bpf_functions,
) )
.unwrap(); .unwrap();
let verified_executable = VerifiedExecutable::< let verified_executable =
TautologyVerifier, VerifiedExecutable::<TautologyVerifier, TestInstructionMeter>::from_executable(
BpfError, executable,
TestInstructionMeter, )
>::from_executable(executable)
.unwrap(); .unwrap();
let input_region = MemoryRegion::new_writable(&mut input_mem, MM_INPUT_START); let input_region = MemoryRegion::new_writable(&mut input_mem, MM_INPUT_START);
let mut vm = EbpfVm::new(&verified_executable, &mut [], vec![input_region]).unwrap(); let mut vm =
EbpfVm::new(&verified_executable, &mut (), &mut [], vec![input_region]).unwrap();
let mut instruction_meter = TestInstructionMeter { remaining: 10 }; let mut instruction_meter = TestInstructionMeter { remaining: 10 };
vm.execute_program_interpreted(&mut instruction_meter) vm.execute_program_interpreted(&mut instruction_meter)
.unwrap(); .unwrap();

View File

@ -23,71 +23,59 @@ struct CallerAccount<'a> {
type TranslatedAccounts<'a> = Vec<(IndexOfAccount, Option<CallerAccount<'a>>)>; type TranslatedAccounts<'a> = Vec<(IndexOfAccount, Option<CallerAccount<'a>>)>;
/// Implemented by language specific data structure translators /// Implemented by language specific data structure translators
trait SyscallInvokeSigned<'a, 'b> { trait SyscallInvokeSigned {
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>>;
fn translate_instruction( fn translate_instruction(
&self,
addr: u64, addr: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError<BpfError>>; ) -> Result<Instruction, EbpfError>;
fn translate_accounts<'c>( fn translate_accounts<'a>(
&'c self,
instruction_accounts: &[InstructionAccount], instruction_accounts: &[InstructionAccount],
program_indices: &[IndexOfAccount], program_indices: &[IndexOfAccount],
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>>; ) -> Result<TranslatedAccounts<'a>, EbpfError>;
fn translate_signers( fn translate_signers(
&self,
program_id: &Pubkey, program_id: &Pubkey,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError<BpfError>>; ) -> Result<Vec<Pubkey>, EbpfError>;
} }
declare_syscall!( declare_syscall!(
/// Cross-program invocation called from Rust /// Cross-program invocation called from Rust
SyscallInvokeSignedRust, SyscallInvokeSignedRust,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
instruction_addr: u64, instruction_addr: u64,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { cpi_common::<Self>(
*result = call( invoke_context,
self,
instruction_addr, instruction_addr,
account_infos_addr, account_infos_addr,
account_infos_len, account_infos_len,
signers_seeds_addr, signers_seeds_addr,
signers_seeds_len, signers_seeds_len,
memory_mapping, memory_mapping,
); )
} }
); );
impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> { impl SyscallInvokeSigned for SyscallInvokeSignedRust {
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>> {
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
}
fn translate_instruction( fn translate_instruction(
&self,
addr: u64, addr: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError<BpfError>> { ) -> Result<Instruction, EbpfError> {
let ix = translate_type::<Instruction>( let ix = translate_type::<Instruction>(
memory_mapping, memory_mapping,
addr, addr,
@ -131,15 +119,14 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
}) })
} }
fn translate_accounts<'c>( fn translate_accounts<'a>(
&'c self,
instruction_accounts: &[InstructionAccount], instruction_accounts: &[InstructionAccount],
program_indices: &[IndexOfAccount], program_indices: &[IndexOfAccount],
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>> { ) -> Result<TranslatedAccounts<'a>, EbpfError> {
let account_infos = translate_slice::<AccountInfo>( let account_infos = translate_slice::<AccountInfo>(
memory_mapping, memory_mapping,
account_infos_addr, account_infos_addr,
@ -157,7 +144,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
) )
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError>>()?;
let translate = |account_info: &AccountInfo, invoke_context: &InvokeContext| { let translate = |account_info: &AccountInfo, invoke_context: &InvokeContext| {
// Translate the account from user space // Translate the account from user space
@ -235,13 +222,12 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
} }
fn translate_signers( fn translate_signers(
&self,
program_id: &Pubkey, program_id: &Pubkey,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError<BpfError>> { ) -> Result<Vec<Pubkey>, EbpfError> {
let mut signers = Vec::new(); let mut signers = Vec::new();
if signers_seeds_len > 0 { if signers_seeds_len > 0 {
let signers_seeds = translate_slice::<&[&[u8]]>( let signers_seeds = translate_slice::<&[&[u8]]>(
@ -279,7 +265,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
invoke_context.get_check_size(), invoke_context.get_check_size(),
) )
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError>>()?;
let signer = Pubkey::create_program_address(&seeds, program_id) let signer = Pubkey::create_program_address(&seeds, program_id)
.map_err(SyscallError::BadSeeds)?; .map_err(SyscallError::BadSeeds)?;
signers.push(signer); signers.push(signer);
@ -347,41 +333,33 @@ struct SolSignerSeedsC {
declare_syscall!( declare_syscall!(
/// Cross-program invocation called from C /// Cross-program invocation called from C
SyscallInvokeSignedC, SyscallInvokeSignedC,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
instruction_addr: u64, instruction_addr: u64,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { cpi_common::<Self>(
*result = call( invoke_context,
self,
instruction_addr, instruction_addr,
account_infos_addr, account_infos_addr,
account_infos_len, account_infos_len,
signers_seeds_addr, signers_seeds_addr,
signers_seeds_len, signers_seeds_len,
memory_mapping, memory_mapping,
); )
} }
); );
impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> { impl SyscallInvokeSigned for SyscallInvokeSignedC {
fn get_context_mut(&self) -> Result<RefMut<&'a mut InvokeContext<'b>>, EbpfError<BpfError>> {
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
}
fn translate_instruction( fn translate_instruction(
&self,
addr: u64, addr: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError<BpfError>> { ) -> Result<Instruction, EbpfError> {
let ix_c = translate_type::<SolInstruction>( let ix_c = translate_type::<SolInstruction>(
memory_mapping, memory_mapping,
addr, addr,
@ -439,7 +417,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
is_writable: meta_c.is_writable, is_writable: meta_c.is_writable,
}) })
}) })
.collect::<Result<Vec<AccountMeta>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<AccountMeta>, EbpfError>>()?;
Ok(Instruction { Ok(Instruction {
program_id: *program_id, program_id: *program_id,
@ -448,15 +426,14 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
}) })
} }
fn translate_accounts<'c>( fn translate_accounts<'a>(
&'c self,
instruction_accounts: &[InstructionAccount], instruction_accounts: &[InstructionAccount],
program_indices: &[IndexOfAccount], program_indices: &[IndexOfAccount],
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<TranslatedAccounts<'c>, EbpfError<BpfError>> { ) -> Result<TranslatedAccounts<'a>, EbpfError> {
let account_infos = translate_slice::<SolAccountInfo>( let account_infos = translate_slice::<SolAccountInfo>(
memory_mapping, memory_mapping,
account_infos_addr, account_infos_addr,
@ -474,7 +451,7 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
) )
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError>>()?;
let translate = |account_info: &SolAccountInfo, invoke_context: &InvokeContext| { let translate = |account_info: &SolAccountInfo, invoke_context: &InvokeContext| {
// Translate the account from user space // Translate the account from user space
@ -551,13 +528,12 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
} }
fn translate_signers( fn translate_signers(
&self,
program_id: &Pubkey, program_id: &Pubkey,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
) -> Result<Vec<Pubkey>, EbpfError<BpfError>> { ) -> Result<Vec<Pubkey>, EbpfError> {
if signers_seeds_len > 0 { if signers_seeds_len > 0 {
let signers_seeds = translate_slice::<SolSignerSeedsC>( let signers_seeds = translate_slice::<SolSignerSeedsC>(
memory_mapping, memory_mapping,
@ -596,11 +572,11 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
invoke_context.get_check_size(), invoke_context.get_check_size(),
) )
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError>>()?;
Pubkey::create_program_address(&seeds_bytes, program_id) Pubkey::create_program_address(&seeds_bytes, program_id)
.map_err(|err| SyscallError::BadSeeds(err).into()) .map_err(|err| SyscallError::BadSeeds(err).into())
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?) .collect::<Result<Vec<_>, EbpfError>>()?)
} else { } else {
Ok(vec![]) Ok(vec![])
} }
@ -614,9 +590,9 @@ fn get_translated_accounts<'a, T, F>(
account_infos: &[T], account_infos: &[T],
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
do_translate: F, do_translate: F,
) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>> ) -> Result<TranslatedAccounts<'a>, EbpfError>
where where
F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError<BpfError>>, F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError>,
{ {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context let instruction_context = transaction_context
@ -686,9 +662,9 @@ where
.set_data_from_slice(caller_account.data) .set_data_from_slice(caller_account.data)
.map_err(SyscallError::InstructionError)?, .map_err(SyscallError::InstructionError)?,
Err(err) if callee_account.get_data() != caller_account.data => { Err(err) if callee_account.get_data() != caller_account.data => {
return Err(EbpfError::UserError(BpfError::SyscallError( return Err(EbpfError::UserError(Box::new(BpfError::SyscallError(
SyscallError::InstructionError(err), SyscallError::InstructionError(err),
))); ))));
} }
_ => {} _ => {}
} }
@ -764,7 +740,7 @@ fn check_instruction_size(
num_accounts: usize, num_accounts: usize,
data_len: usize, data_len: usize,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<(), EbpfError<BpfError>> { ) -> Result<(), EbpfError> {
if invoke_context if invoke_context
.feature_set .feature_set
.is_active(&feature_set::loosen_cpi_size_restriction::id()) .is_active(&feature_set::loosen_cpi_size_restriction::id())
@ -803,7 +779,7 @@ fn check_instruction_size(
fn check_account_infos( fn check_account_infos(
num_account_infos: usize, num_account_infos: usize,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<(), EbpfError<BpfError>> { ) -> Result<(), EbpfError> {
if invoke_context if invoke_context
.feature_set .feature_set
.is_active(&feature_set::loosen_cpi_size_restriction::id()) .is_active(&feature_set::loosen_cpi_size_restriction::id())
@ -850,7 +826,7 @@ fn check_authorized_program(
program_id: &Pubkey, program_id: &Pubkey,
instruction_data: &[u8], instruction_data: &[u8],
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
) -> Result<(), EbpfError<BpfError>> { ) -> Result<(), EbpfError> {
if native_loader::check_id(program_id) if native_loader::check_id(program_id)
|| bpf_loader::check_id(program_id) || bpf_loader::check_id(program_id)
|| bpf_loader_deprecated::check_id(program_id) || bpf_loader_deprecated::check_id(program_id)
@ -868,23 +844,21 @@ fn check_authorized_program(
} }
/// Call process instruction, common to both Rust and C /// Call process instruction, common to both Rust and C
fn call<'a, 'b: 'a>( fn cpi_common<S: SyscallInvokeSigned>(
syscall: &mut dyn SyscallInvokeSigned<'a, 'b>, invoke_context: &mut InvokeContext,
instruction_addr: u64, instruction_addr: u64,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
signers_seeds_addr: u64, signers_seeds_addr: u64,
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
) -> Result<u64, EbpfError<BpfError>> { ) -> Result<u64, EbpfError> {
let mut invoke_context = syscall.get_context_mut()?;
invoke_context invoke_context
.get_compute_meter() .get_compute_meter()
.consume(invoke_context.get_compute_budget().invoke_units)?; .consume(invoke_context.get_compute_budget().invoke_units)?;
// Translate and verify caller's data // Translate and verify caller's data
let instruction = let instruction = S::translate_instruction(instruction_addr, memory_mapping, invoke_context)?;
syscall.translate_instruction(instruction_addr, memory_mapping, *invoke_context)?;
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context let instruction_context = transaction_context
.get_current_instruction_context() .get_current_instruction_context()
@ -892,24 +866,24 @@ fn call<'a, 'b: 'a>(
let caller_program_id = instruction_context let caller_program_id = instruction_context
.get_last_program_key(transaction_context) .get_last_program_key(transaction_context)
.map_err(SyscallError::InstructionError)?; .map_err(SyscallError::InstructionError)?;
let signers = syscall.translate_signers( let signers = S::translate_signers(
caller_program_id, caller_program_id,
signers_seeds_addr, signers_seeds_addr,
signers_seeds_len, signers_seeds_len,
memory_mapping, memory_mapping,
*invoke_context, invoke_context,
)?; )?;
let (instruction_accounts, program_indices) = invoke_context let (instruction_accounts, program_indices) = invoke_context
.prepare_instruction(&instruction, &signers) .prepare_instruction(&instruction, &signers)
.map_err(SyscallError::InstructionError)?; .map_err(SyscallError::InstructionError)?;
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?; check_authorized_program(&instruction.program_id, &instruction.data, invoke_context)?;
let mut accounts = syscall.translate_accounts( let mut accounts = S::translate_accounts(
&instruction_accounts, &instruction_accounts,
&program_indices, &program_indices,
account_infos_addr, account_infos_addr,
account_infos_len, account_infos_len,
memory_mapping, memory_mapping,
*invoke_context, invoke_context,
)?; )?;
// Process instruction // Process instruction

View File

@ -3,29 +3,21 @@ use {super::*, crate::declare_syscall};
declare_syscall!( declare_syscall!(
/// Log a user's info message /// Log a user's info message
SyscallLog, SyscallLog,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
addr: u64, addr: u64,
len: u64, len: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context let cost = invoke_context
.get_compute_budget() .get_compute_budget()
.syscall_base_cost .syscall_base_cost
.max(len); .max(len);
question_mark!(invoke_context.get_compute_meter().consume(cost), result); invoke_context.get_compute_meter().consume(cost)?;
question_mark!(
translate_string_and_do( translate_string_and_do(
memory_mapping, memory_mapping,
addr, addr,
@ -35,35 +27,26 @@ declare_syscall!(
&mut |string: &str| { &mut |string: &str| {
stable_log::program_log(&invoke_context.get_log_collector(), string); stable_log::program_log(&invoke_context.get_log_collector(), string);
Ok(0) Ok(0)
} },
), )?;
result Ok(0)
);
*result = Ok(0);
} }
); );
declare_syscall!( declare_syscall!(
/// Log 5 64-bit values /// Log 5 64-bit values
SyscallLogU64, SyscallLogU64,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
arg1: u64, arg1: u64,
arg2: u64, arg2: u64,
arg3: u64, arg3: u64,
arg4: u64, arg4: u64,
arg5: u64, arg5: u64,
_memory_mapping: &mut MemoryMapping, _memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context.get_compute_budget().log_64_units; let cost = invoke_context.get_compute_budget().log_64_units;
question_mark!(invoke_context.get_compute_meter().consume(cost), result); invoke_context.get_compute_meter().consume(cost)?;
stable_log::program_log( stable_log::program_log(
&invoke_context.get_log_collector(), &invoke_context.get_log_collector(),
@ -72,151 +55,112 @@ declare_syscall!(
arg1, arg2, arg3, arg4, arg5 arg1, arg2, arg3, arg4, arg5
), ),
); );
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// Log current compute consumption /// Log current compute consumption
SyscallLogBpfComputeUnits, SyscallLogBpfComputeUnits,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
_arg1: u64, _arg1: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
_memory_mapping: &mut MemoryMapping, _memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context.get_compute_budget().syscall_base_cost; let cost = invoke_context.get_compute_budget().syscall_base_cost;
question_mark!(invoke_context.get_compute_meter().consume(cost), result); invoke_context.get_compute_meter().consume(cost)?;
ic_logger_msg!( ic_logger_msg!(
invoke_context.get_log_collector(), invoke_context.get_log_collector(),
"Program consumption: {} units remaining", "Program consumption: {} units remaining",
invoke_context.get_compute_meter().borrow().get_remaining() invoke_context.get_compute_meter().borrow().get_remaining()
); );
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// Log 5 64-bit values /// Log 5 64-bit values
SyscallLogPubkey, SyscallLogPubkey,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
pubkey_addr: u64, pubkey_addr: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context.get_compute_budget().log_pubkey_units; let cost = invoke_context.get_compute_budget().log_pubkey_units;
question_mark!(invoke_context.get_compute_meter().consume(cost), result); invoke_context.get_compute_meter().consume(cost)?;
let pubkey = question_mark!( let pubkey = translate_type::<Pubkey>(
translate_type::<Pubkey>(
memory_mapping, memory_mapping,
pubkey_addr, pubkey_addr,
invoke_context.get_check_aligned() invoke_context.get_check_aligned(),
), )?;
result
);
stable_log::program_log(&invoke_context.get_log_collector(), &pubkey.to_string()); stable_log::program_log(&invoke_context.get_log_collector(), &pubkey.to_string());
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// Log data handling /// Log data handling
SyscallLogData, SyscallLogData,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
addr: u64, addr: u64,
len: u64, len: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let budget = invoke_context.get_compute_budget(); let budget = invoke_context.get_compute_budget();
question_mark!(
invoke_context invoke_context
.get_compute_meter() .get_compute_meter()
.consume(budget.syscall_base_cost), .consume(budget.syscall_base_cost)?;
result
);
let untranslated_fields = question_mark!( let untranslated_fields = translate_slice::<&[u8]>(
translate_slice::<&[u8]>(
memory_mapping, memory_mapping,
addr, addr,
len, len,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size(), invoke_context.get_check_size(),
), )?;
result
);
question_mark!(
invoke_context.get_compute_meter().consume( invoke_context.get_compute_meter().consume(
budget budget
.syscall_base_cost .syscall_base_cost
.saturating_mul(untranslated_fields.len() as u64) .saturating_mul(untranslated_fields.len() as u64),
), )?;
result
);
question_mark!(
invoke_context.get_compute_meter().consume( invoke_context.get_compute_meter().consume(
untranslated_fields untranslated_fields
.iter() .iter()
.fold(0, |total, e| total.saturating_add(e.len() as u64)) .fold(0, |total, e| total.saturating_add(e.len() as u64)),
), )?;
result
);
let mut fields = Vec::with_capacity(untranslated_fields.len()); let mut fields = Vec::with_capacity(untranslated_fields.len());
for untranslated_field in untranslated_fields { for untranslated_field in untranslated_fields {
fields.push(question_mark!( fields.push(translate_slice::<u8>(
translate_slice::<u8>(
memory_mapping, memory_mapping,
untranslated_field.as_ptr() as *const _ as u64, untranslated_field.as_ptr() as *const _ as u64,
untranslated_field.len() as u64, untranslated_field.len() as u64,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size(), invoke_context.get_check_size(),
), )?);
result
));
} }
let log_collector = invoke_context.get_log_collector(); let log_collector = invoke_context.get_log_collector();
stable_log::program_data(&log_collector, &fields); stable_log::program_data(&log_collector, &fields);
*result = Ok(0); Ok(0)
} }
); );

View File

@ -1,9 +1,6 @@
use {super::*, crate::declare_syscall}; use {super::*, crate::declare_syscall};
fn mem_op_consume<'a, 'b>( fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), EbpfError> {
invoke_context: &Ref<&'a mut InvokeContext<'b>>,
n: u64,
) -> Result<(), EbpfError<BpfError>> {
let compute_budget = invoke_context.get_compute_budget(); let compute_budget = invoke_context.get_compute_budget();
let cost = compute_budget let cost = compute_budget
.mem_op_base_cost .mem_op_base_cost
@ -14,54 +11,40 @@ fn mem_op_consume<'a, 'b>(
declare_syscall!( declare_syscall!(
/// memcpy /// memcpy
SyscallMemcpy, SyscallMemcpy,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
dst_addr: u64, dst_addr: u64,
src_addr: u64, src_addr: u64,
n: u64, n: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { mem_op_consume(invoke_context, n)?;
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
question_mark!(mem_op_consume(&invoke_context, n), result);
let do_check_physical_overlapping = invoke_context let do_check_physical_overlapping = invoke_context
.feature_set .feature_set
.is_active(&check_physical_overlapping::id()); .is_active(&check_physical_overlapping::id());
if !is_nonoverlapping(src_addr, dst_addr, n) { if !is_nonoverlapping(src_addr, dst_addr, n) {
*result = Err(SyscallError::CopyOverlapping.into()); return Err(SyscallError::CopyOverlapping.into());
return;
} }
let dst_ptr = question_mark!( let dst_ptr = translate_slice_mut::<u8>(
translate_slice_mut::<u8>(
memory_mapping, memory_mapping,
dst_addr, dst_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size() invoke_context.get_check_size(),
), )?
result
)
.as_mut_ptr(); .as_mut_ptr();
let src_ptr = question_mark!( let src_ptr = translate_slice::<u8>(
translate_slice::<u8>(
memory_mapping, memory_mapping,
src_addr, src_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size() invoke_context.get_check_size(),
), )?
result
)
.as_ptr(); .as_ptr();
if do_check_physical_overlapping if do_check_physical_overlapping
&& !is_nonoverlapping(src_ptr as usize, dst_ptr as usize, n as usize) && !is_nonoverlapping(src_ptr as usize, dst_ptr as usize, n as usize)
@ -74,111 +57,82 @@ declare_syscall!(
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, n as usize); std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, n as usize);
} }
} }
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// memmove /// memmove
SyscallMemmove, SyscallMemmove,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
dst_addr: u64, dst_addr: u64,
src_addr: u64, src_addr: u64,
n: u64, n: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { mem_op_consume(invoke_context, n)?;
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
question_mark!(mem_op_consume(&invoke_context, n), result);
let dst = question_mark!( let dst = translate_slice_mut::<u8>(
translate_slice_mut::<u8>(
memory_mapping, memory_mapping,
dst_addr, dst_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size() invoke_context.get_check_size(),
), )?;
result let src = translate_slice::<u8>(
);
let src = question_mark!(
translate_slice::<u8>(
memory_mapping, memory_mapping,
src_addr, src_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size() invoke_context.get_check_size(),
), )?;
result
);
unsafe { unsafe {
std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize); std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize);
} }
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// memcmp /// memcmp
SyscallMemcmp, SyscallMemcmp,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
s1_addr: u64, s1_addr: u64,
s2_addr: u64, s2_addr: u64,
n: u64, n: u64,
cmp_result_addr: u64, cmp_result_addr: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { mem_op_consume(invoke_context, n)?;
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
question_mark!(mem_op_consume(&invoke_context, n), result);
let s1 = question_mark!( let s1 = translate_slice::<u8>(
translate_slice::<u8>(
memory_mapping, memory_mapping,
s1_addr, s1_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size(), invoke_context.get_check_size(),
), )?;
result let s2 = translate_slice::<u8>(
);
let s2 = question_mark!(
translate_slice::<u8>(
memory_mapping, memory_mapping,
s2_addr, s2_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size(), invoke_context.get_check_size(),
), )?;
result let cmp_result = translate_type_mut::<i32>(
);
let cmp_result = question_mark!(
translate_type_mut::<i32>(
memory_mapping, memory_mapping,
cmp_result_addr, cmp_result_addr,
invoke_context.get_check_aligned() invoke_context.get_check_aligned(),
), )?;
result
);
let mut i = 0; let mut i = 0;
while i < n as usize { while i < n as usize {
let a = *question_mark!(s1.get(i).ok_or(SyscallError::InvalidLength,), result); let a = *s1.get(i).ok_or(SyscallError::InvalidLength)?;
let b = *question_mark!(s2.get(i).ok_or(SyscallError::InvalidLength,), result); let b = *s2.get(i).ok_or(SyscallError::InvalidLength)?;
if a != b { if a != b {
*cmp_result = if invoke_context *cmp_result = if invoke_context
.feature_set .feature_set
@ -191,50 +145,39 @@ declare_syscall!(
a as i32 - b as i32 a as i32 - b as i32
} }
}; };
*result = Ok(0); return Ok(0);
return;
}; };
i = i.saturating_add(1); i = i.saturating_add(1);
} }
*cmp_result = 0; *cmp_result = 0;
*result = Ok(0); Ok(0)
} }
); );
declare_syscall!( declare_syscall!(
/// memset /// memset
SyscallMemset, SyscallMemset,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
s_addr: u64, s_addr: u64,
c: u64, c: u64,
n: u64, n: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { mem_op_consume(invoke_context, n)?;
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
question_mark!(mem_op_consume(&invoke_context, n), result);
let s = question_mark!( let s = translate_slice_mut::<u8>(
translate_slice_mut::<u8>(
memory_mapping, memory_mapping,
s_addr, s_addr,
n, n,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
invoke_context.get_check_size(), invoke_context.get_check_size(),
), )?;
result
);
for val in s.iter_mut().take(n as usize) { for val in s.iter_mut().take(n as usize) {
*val = c as u8; *val = c as u8;
} }
*result = Ok(0); Ok(0)
} }
); );

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
check_aligned: bool, check_aligned: bool,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext, invoke_context: &mut InvokeContext,
) -> Result<u64, EbpfError<BpfError>> { ) -> Result<u64, EbpfError> {
invoke_context.get_compute_meter().consume( invoke_context.get_compute_meter().consume(
invoke_context invoke_context
.get_compute_budget() .get_compute_budget()
@ -24,89 +24,68 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId + Clone>(
declare_syscall!( declare_syscall!(
/// Get a Clock sysvar /// Get a Clock sysvar
SyscallGetClockSysvar, SyscallGetClockSysvar,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
var_addr: u64, var_addr: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { get_sysvar(
let mut invoke_context = question_mark!(
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
*result = get_sysvar(
invoke_context.get_sysvar_cache().get_clock(), invoke_context.get_sysvar_cache().get_clock(),
var_addr, var_addr,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
memory_mapping, memory_mapping,
&mut invoke_context, invoke_context,
); )
} }
); );
declare_syscall!( declare_syscall!(
/// Get a EpochSchedule sysvar /// Get a EpochSchedule sysvar
SyscallGetEpochScheduleSysvar, SyscallGetEpochScheduleSysvar,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
var_addr: u64, var_addr: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { get_sysvar(
let mut invoke_context = question_mark!(
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
*result = get_sysvar(
invoke_context.get_sysvar_cache().get_epoch_schedule(), invoke_context.get_sysvar_cache().get_epoch_schedule(),
var_addr, var_addr,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
memory_mapping, memory_mapping,
&mut invoke_context, invoke_context,
); )
} }
); );
declare_syscall!( declare_syscall!(
/// Get a Fees sysvar /// Get a Fees sysvar
SyscallGetFeesSysvar, SyscallGetFeesSysvar,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
var_addr: u64, var_addr: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) {
let mut invoke_context = question_mark!(
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
#[allow(deprecated)] #[allow(deprecated)]
{ {
*result = get_sysvar( get_sysvar(
invoke_context.get_sysvar_cache().get_fees(), invoke_context.get_sysvar_cache().get_fees(),
var_addr, var_addr,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
memory_mapping, memory_mapping,
&mut invoke_context, invoke_context,
); )
} }
} }
); );
@ -114,28 +93,21 @@ declare_syscall!(
declare_syscall!( declare_syscall!(
/// Get a Rent sysvar /// Get a Rent sysvar
SyscallGetRentSysvar, SyscallGetRentSysvar,
fn call( fn inner_call(
&mut self, invoke_context: &mut InvokeContext,
var_addr: u64, var_addr: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
_arg4: u64, _arg4: u64,
_arg5: u64, _arg5: u64,
memory_mapping: &mut MemoryMapping, memory_mapping: &mut MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>, ) -> Result<u64, EbpfError> {
) { get_sysvar(
let mut invoke_context = question_mark!(
self.invoke_context
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
*result = get_sysvar(
invoke_context.get_sysvar_cache().get_rent(), invoke_context.get_sysvar_cache().get_rent(),
var_addr, var_addr,
invoke_context.get_check_aligned(), invoke_context.get_check_aligned(),
memory_mapping, memory_mapping,
&mut invoke_context, invoke_context,
); )
} }
); );

View File

@ -17,4 +17,4 @@ solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.15.
solana-logger = { path = "../logger", version = "=1.15.0" } solana-logger = { path = "../logger", version = "=1.15.0" }
solana-program-runtime = { path = "../program-runtime", version = "=1.15.0" } solana-program-runtime = { path = "../program-runtime", version = "=1.15.0" }
solana-sdk = { path = "../sdk", version = "=1.15.0" } solana-sdk = { path = "../sdk", version = "=1.15.0" }
solana_rbpf = "=0.2.33" solana_rbpf = "=0.2.34"

View File

@ -3,7 +3,7 @@ use {
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
serde_json::Result, serde_json::Result,
solana_bpf_loader_program::{ solana_bpf_loader_program::{
create_vm, serialization::serialize_parameters, syscalls::register_syscalls, BpfError, create_vm, serialization::serialize_parameters, syscalls::register_syscalls,
ThisInstructionMeter, ThisInstructionMeter,
}, },
solana_program_runtime::invoke_context::{prepare_mock_invoke_context, InvokeContext}, solana_program_runtime::invoke_context::{prepare_mock_invoke_context, InvokeContext},
@ -254,10 +254,10 @@ native machine code before execting it in the virtual machine.",
file.read_to_end(&mut contents).unwrap(); file.read_to_end(&mut contents).unwrap();
let syscall_registry = register_syscalls(&mut invoke_context, true).unwrap(); let syscall_registry = register_syscalls(&mut invoke_context, true).unwrap();
let executable = if magic == [0x7f, 0x45, 0x4c, 0x46] { let executable = if magic == [0x7f, 0x45, 0x4c, 0x46] {
Executable::<BpfError, ThisInstructionMeter>::from_elf(&contents, config, syscall_registry) Executable::<ThisInstructionMeter>::from_elf(&contents, config, syscall_registry)
.map_err(|err| format!("Executable constructor failed: {:?}", err)) .map_err(|err| format!("Executable constructor failed: {:?}", err))
} else { } else {
assemble::<BpfError, ThisInstructionMeter>( assemble::<ThisInstructionMeter>(
std::str::from_utf8(contents.as_slice()).unwrap(), std::str::from_utf8(contents.as_slice()).unwrap(),
config, config,
syscall_registry, syscall_registry,
@ -266,9 +266,7 @@ native machine code before execting it in the virtual machine.",
.unwrap(); .unwrap();
let mut verified_executable = let mut verified_executable =
VerifiedExecutable::<RequisiteVerifier, BpfError, ThisInstructionMeter>::from_executable( VerifiedExecutable::<RequisiteVerifier, ThisInstructionMeter>::from_executable(executable)
executable,
)
.map_err(|err| format!("Executable verifier failed: {:?}", err)) .map_err(|err| format!("Executable verifier failed: {:?}", err))
.unwrap(); .unwrap();
@ -310,13 +308,14 @@ native machine code before execting it in the virtual machine.",
if matches.is_present("trace") { if matches.is_present("trace") {
eprintln!("Trace is saved in trace.out"); eprintln!("Trace is saved in trace.out");
let mut file = File::create("trace.out").unwrap(); let mut file = File::create("trace.out").unwrap();
vm.get_tracer() vm.get_program_environment()
.tracer
.write(&mut file, analysis.analyze()) .write(&mut file, analysis.analyze())
.unwrap(); .unwrap();
} }
if matches.is_present("profile") { if matches.is_present("profile") {
eprintln!("Profile is saved in profile.dot"); eprintln!("Profile is saved in profile.dot");
let tracer = &vm.get_tracer(); let tracer = &vm.get_program_environment().tracer;
let analysis = analysis.analyze(); let analysis = analysis.analyze();
let dynamic_analysis = DynamicAnalysis::new(tracer, analysis); let dynamic_analysis = DynamicAnalysis::new(tracer, analysis);
let mut file = File::create("profile.dot").unwrap(); let mut file = File::create("profile.dot").unwrap();
@ -376,19 +375,19 @@ impl Debug for Output {
// Replace with std::lazy::Lazy when stabilized. // Replace with std::lazy::Lazy when stabilized.
// https://github.com/rust-lang/rust/issues/74465 // https://github.com/rust-lang/rust/issues/74465
struct LazyAnalysis<'a> { struct LazyAnalysis<'a> {
analysis: Option<Analysis<'a, BpfError, ThisInstructionMeter>>, analysis: Option<Analysis<'a, ThisInstructionMeter>>,
executable: &'a Executable<BpfError, ThisInstructionMeter>, executable: &'a Executable<ThisInstructionMeter>,
} }
impl<'a> LazyAnalysis<'a> { impl<'a> LazyAnalysis<'a> {
fn new(executable: &'a Executable<BpfError, ThisInstructionMeter>) -> Self { fn new(executable: &'a Executable<ThisInstructionMeter>) -> Self {
Self { Self {
analysis: None, analysis: None,
executable, executable,
} }
} }
fn analyze(&mut self) -> &Analysis<BpfError, ThisInstructionMeter> { fn analyze(&mut self) -> &Analysis<ThisInstructionMeter> {
if let Some(ref analysis) = self.analysis { if let Some(ref analysis) = self.analysis {
return analysis; return analysis;
} }