Skip to content

Commit

Permalink
Ensure that hashing across account data and resize area works
Browse files Browse the repository at this point in the history
  • Loading branch information
seanyoung committed Dec 3, 2024
1 parent 54a254f commit d5f28a1
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 12 deletions.
4 changes: 2 additions & 2 deletions programs/bpf_loader/src/syscalls/mem_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ where
Ok(T::default())
}

struct MemoryChunkIterator<'a> {
pub struct MemoryChunkIterator<'a> {
memory_mapping: &'a MemoryMapping<'a>,
accounts: &'a [SerializedAccountMetadata],
access_type: AccessType,
Expand All @@ -424,7 +424,7 @@ struct MemoryChunkIterator<'a> {
}

impl<'a> MemoryChunkIterator<'a> {
fn new(
pub fn new(
memory_mapping: &'a MemoryMapping,
accounts: &'a [SerializedAccountMetadata],
access_type: AccessType,
Expand Down
53 changes: 43 additions & 10 deletions programs/bpf_loader/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub use self::{
logging::{
SyscallLog, SyscallLogBpfComputeUnits, SyscallLogData, SyscallLogPubkey, SyscallLogU64,
},
mem_ops::{SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
mem_ops::{MemoryChunkIterator, SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
sysvar::{
SyscallGetClockSysvar, SyscallGetEpochRewardsSysvar, SyscallGetEpochScheduleSysvar,
SyscallGetFeesSysvar, SyscallGetLastRestartSlotSysvar, SyscallGetRentSysvar,
Expand Down Expand Up @@ -2009,6 +2009,9 @@ declare_builtin_function!(
std::mem::size_of::<H::Output>() as u64,
invoke_context.get_check_aligned(),
)?;
let direct_mapping = invoke_context
.get_feature_set()
.is_active(&solana_feature_set::bpf_account_data_direct_mapping::id());
let mut hasher = H::create_hasher();
if vals_len > 0 {
let vals = translate_slice::<&[u8]>(
Expand All @@ -2018,12 +2021,32 @@ declare_builtin_function!(
invoke_context.get_check_aligned(),
)?;
for val in vals.iter() {
let bytes = translate_slice::<u8>(
memory_mapping,
val.as_ptr() as u64,
val.len() as u64,
invoke_context.get_check_aligned(),
)?;
if direct_mapping {
let syscall_context = invoke_context.get_syscall_context()?;

let chunk_iter = MemoryChunkIterator::new(memory_mapping, &syscall_context.accounts_metadata, AccessType::Load, val.as_ptr() as u64, val.len() as u64)?;

for item in chunk_iter {
let (region, src_addr, chunk_len) = item?;

let addr = Result::from(region.vm_to_host(src_addr, chunk_len as u64))?;

let bytes = unsafe {
std::slice::from_raw_parts(addr as *const u8, chunk_len)
};

hasher.hash(bytes);
}
} else {
let bytes = translate_slice::<u8>(
memory_mapping,
val.as_ptr() as u64,
val.len() as u64,
invoke_context.get_check_aligned(),
)?;
hasher.hash(bytes);
}

let cost = compute_budget.mem_op_base_cost.max(
hash_byte_cost.saturating_mul(
(val.len() as u64)
Expand All @@ -2032,8 +2055,8 @@ declare_builtin_function!(
),
);
consume_compute_meter(invoke_context, cost)?;
hasher.hash(bytes);
}
}

}
hash_result.copy_from_slice(hasher.result().as_ref());
Ok(0)
Expand Down Expand Up @@ -2119,7 +2142,10 @@ mod tests {
crate::mock_create_vm,
assert_matches::assert_matches,
core::slice,
solana_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context},
solana_program_runtime::{
invoke_context::{BpfAllocator, InvokeContext},
with_mock_invoke_context,
},
solana_rbpf::{
error::EbpfError, memory_region::MemoryRegion, program::SBPFVersion, vm::Config,
},
Expand Down Expand Up @@ -2675,6 +2701,13 @@ mod tests {
fn test_syscall_sha256() {
let config = Config::default();
prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
invoke_context
.set_syscall_context(SyscallContext {
allocator: BpfAllocator::new(32168),
accounts_metadata: Vec::new(),
trace_log: Vec::new(),
})
.unwrap();

let bytes1 = "Gaggablaghblagh!";
let bytes2 = "flurbos";
Expand Down
25 changes: 25 additions & 0 deletions programs/sbf/rust/account_mem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use solana_program::{
account_info::AccountInfo,
blake3,
entrypoint::ProgramResult,
program_error::ProgramError,
program_memory::{sol_memcmp, sol_memcpy, sol_memmove, sol_memset},
Expand Down Expand Up @@ -109,6 +110,30 @@ pub fn process_instruction(
unsafe { sol_memmove(too_early(3).as_mut_ptr(), buf.as_ptr(), 10) };
}

20 => {
use solana_program::hash::{hashv, Hasher};

let mut hasher = Hasher::default();
hasher.hashv(&[data]);

assert_eq!(hashv(&[data]), hasher.result());
}

21 => {
use solana_program::keccak::{hashv, Hasher};

let mut hasher = Hasher::default();
hasher.hashv(&[data]);

assert_eq!(hashv(&[data]), hasher.result());
}

22 => {
use solana_program::blake3::hashv;

let hash = blake3::hash(data);
assert_eq!(hashv(&[data]).0, hash.to_bytes());
}
_ => {}
}

Expand Down
20 changes: 20 additions & 0 deletions programs/sbf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5501,5 +5501,25 @@ fn test_mem_syscalls_overlap_account_begin_or_end() {
assert!(!logs.last().unwrap().ends_with(" failed: InvalidLength"));
}
}

// now test the hashing functions

for instr in 20..=22 {
println!("Testing direct_mapping:{direct_mapping} instruction:{instr}");
let instruction =
Instruction::new_with_bytes(program_id, &[instr], account_metas.clone());

let message = Message::new(
&[
instruction,
ComputeBudgetInstruction::set_compute_unit_limit(1_000_000_000),
],
Some(&mint_pubkey),
);
let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
let (result, _, _logs) = process_transaction_and_record_inner(&bank, tx);

assert!(result.is_ok());
}
}
}

0 comments on commit d5f28a1

Please sign in to comment.