updated inner_call for hashing fn to follow generic approach (#33128)

* updated inner_call for hashing fn to follow generic approach

* different hash compute budget values for all digests

* fixed conflicts

* reverted changes to compute_budget.rs and added 3method to trait to get compute budget values

* updated type for result fn for HasherImpl

* using Hash directly in result fn, got rid of HASH_BYTES and removed comment form compute_budget

* updated import statement

* cargo fmt -all

* removed unused import and reference related warning

* oops forgot semicolon

* removed trailing white space
This commit is contained in:
Sanjay Singh 2023-10-14 02:23:19 +05:30 committed by GitHub
parent a3f85aba21
commit a60d1857bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 202 additions and 205 deletions

View File

@ -43,7 +43,7 @@ use {
remaining_compute_units_syscall_enabled, stop_sibling_instruction_search_at_parent,
stop_truncating_strings_in_syscalls, switch_to_new_elf_parser,
},
hash::{Hasher, HASH_BYTES},
hash::{Hash, Hasher},
instruction::{
AccountMeta, InstructionError, ProcessedSiblingInstruction,
TRANSACTION_LEVEL_STACK_HEIGHT,
@ -132,6 +132,103 @@ pub enum SyscallError {
type Error = Box<dyn std::error::Error>;
pub trait HasherImpl {
const NAME: &'static str;
type Output: AsRef<[u8]>;
fn create_hasher() -> Self;
fn hash(&mut self, val: &[u8]);
fn result(self) -> Self::Output;
fn get_base_cost(compute_budget: &ComputeBudget) -> u64;
fn get_byte_cost(compute_budget: &ComputeBudget) -> u64;
fn get_max_slices(compute_budget: &ComputeBudget) -> u64;
}
pub struct Sha256Hasher(Hasher);
pub struct Blake3Hasher(blake3::Hasher);
pub struct Keccak256Hasher(keccak::Hasher);
impl HasherImpl for Sha256Hasher {
const NAME: &'static str = "Sha256";
type Output = Hash;
fn create_hasher() -> Self {
Sha256Hasher(Hasher::default())
}
fn hash(&mut self, val: &[u8]) {
self.0.hash(val);
}
fn result(self) -> Self::Output {
self.0.result()
}
fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_base_cost
}
fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_byte_cost
}
fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_max_slices
}
}
impl HasherImpl for Blake3Hasher {
const NAME: &'static str = "Blake3";
type Output = blake3::Hash;
fn create_hasher() -> Self {
Blake3Hasher(blake3::Hasher::default())
}
fn hash(&mut self, val: &[u8]) {
self.0.hash(val);
}
fn result(self) -> Self::Output {
self.0.result()
}
fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_base_cost
}
fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_byte_cost
}
fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_max_slices
}
}
impl HasherImpl for Keccak256Hasher {
const NAME: &'static str = "Keccak256";
type Output = keccak::Hash;
fn create_hasher() -> Self {
Keccak256Hasher(keccak::Hasher::default())
}
fn hash(&mut self, val: &[u8]) {
self.0.hash(val);
}
fn result(self) -> Self::Output {
self.0.result()
}
fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_base_cost
}
fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_byte_cost
}
fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
compute_budget.sha256_max_slices
}
}
fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> {
invoke_context.consume_checked(amount)?;
Ok(())
@ -220,10 +317,10 @@ pub fn create_program_runtime_environment_v1<'a>(
)?;
// Sha256
result.register_function_hashed(*b"sol_sha256", SyscallSha256::call)?;
result.register_function_hashed(*b"sol_sha256", SyscallHash::call::<Sha256Hasher>)?;
// Keccak256
result.register_function_hashed(*b"sol_keccak256", SyscallKeccak256::call)?;
result.register_function_hashed(*b"sol_keccak256", SyscallHash::call::<Keccak256Hasher>)?;
// Secp256k1 Recover
result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?;
@ -233,7 +330,7 @@ pub fn create_program_runtime_environment_v1<'a>(
result,
blake3_syscall_enabled,
*b"sol_blake3",
SyscallBlake3::call,
SyscallHash::call::<Blake3Hasher>,
)?;
// Elliptic Curve Operations
@ -519,6 +616,32 @@ macro_rules! declare_syscall {
};
}
#[macro_export]
macro_rules! declare_syscallhash {
($(#[$attr:meta])* $name:ident, $inner_call:item) => {
$(#[$attr])*
pub struct $name {}
impl $name {
$inner_call
pub fn call<H: HasherImpl>(
invoke_context: &mut InvokeContext,
arg_a: u64,
arg_b: u64,
arg_c: u64,
arg_d: u64,
arg_e: u64,
memory_mapping: &mut MemoryMapping,
result: &mut ProgramResult,
) {
let converted_result: ProgramResult = Self::inner_call::<H>(
invoke_context, arg_a, arg_b, arg_c, arg_d, arg_e, memory_mapping,
).into();
*result = converted_result;
}
}
};
}
declare_syscall!(
/// Abort syscall functions, called when the SBF program calls `abort()`
/// LLVM will insert calls to `abort()` if it detects an untenable situation,
@ -750,136 +873,6 @@ declare_syscall!(
}
);
declare_syscall!(
/// SHA256
SyscallSha256,
fn inner_call(
invoke_context: &mut InvokeContext,
vals_addr: u64,
vals_len: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
invoke_context,
"Sha256 hashing {} sequences in one syscall is over the limit {}",
vals_len,
compute_budget.sha256_max_slices,
);
return Err(SyscallError::TooManySlices.into());
}
consume_compute_meter(invoke_context, compute_budget.sha256_base_cost)?;
let hash_result = translate_slice_mut::<u8>(
memory_mapping,
result_addr,
HASH_BYTES as u64,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let mut hasher = Hasher::default();
if vals_len > 0 {
let vals = translate_slice::<&[u8]>(
memory_mapping,
vals_addr,
vals_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
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(),
invoke_context.get_check_size(),
)?;
let cost = compute_budget.mem_op_base_cost.max(
compute_budget.sha256_byte_cost.saturating_mul(
(val.len() as u64)
.checked_div(2)
.expect("div by non-zero literal"),
),
);
consume_compute_meter(invoke_context, cost)?;
hasher.hash(bytes);
}
}
hash_result.copy_from_slice(&hasher.result().to_bytes());
Ok(0)
}
);
declare_syscall!(
// Keccak256
SyscallKeccak256,
fn inner_call(
invoke_context: &mut InvokeContext,
vals_addr: u64,
vals_len: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
invoke_context,
"Keccak256 hashing {} sequences in one syscall is over the limit {}",
vals_len,
compute_budget.sha256_max_slices,
);
return Err(SyscallError::TooManySlices.into());
}
consume_compute_meter(invoke_context, compute_budget.sha256_base_cost)?;
let hash_result = translate_slice_mut::<u8>(
memory_mapping,
result_addr,
keccak::HASH_BYTES as u64,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let mut hasher = keccak::Hasher::default();
if vals_len > 0 {
let vals = translate_slice::<&[u8]>(
memory_mapping,
vals_addr,
vals_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
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(),
invoke_context.get_check_size(),
)?;
let cost = compute_budget.mem_op_base_cost.max(
compute_budget.sha256_byte_cost.saturating_mul(
(val.len() as u64)
.checked_div(2)
.expect("div by non-zero literal"),
),
);
consume_compute_meter(invoke_context, cost)?;
hasher.hash(bytes);
}
}
hash_result.copy_from_slice(&hasher.result().to_bytes());
Ok(0)
}
);
declare_syscall!(
/// secp256k1_recover
SyscallSecp256k1Recover,
@ -1314,71 +1307,6 @@ declare_syscall!(
}
);
declare_syscall!(
// Blake3
SyscallBlake3,
fn inner_call(
invoke_context: &mut InvokeContext,
vals_addr: u64,
vals_len: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
if compute_budget.sha256_max_slices < vals_len {
ic_msg!(
invoke_context,
"Blake3 hashing {} sequences in one syscall is over the limit {}",
vals_len,
compute_budget.sha256_max_slices,
);
return Err(SyscallError::TooManySlices.into());
}
consume_compute_meter(invoke_context, compute_budget.sha256_base_cost)?;
let hash_result = translate_slice_mut::<u8>(
memory_mapping,
result_addr,
blake3::HASH_BYTES as u64,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let mut hasher = blake3::Hasher::default();
if vals_len > 0 {
let vals = translate_slice::<&[u8]>(
memory_mapping,
vals_addr,
vals_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
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(),
invoke_context.get_check_size(),
)?;
let cost = compute_budget.mem_op_base_cost.max(
compute_budget.sha256_byte_cost.saturating_mul(
(val.len() as u64)
.checked_div(2)
.expect("div by non-zero literal"),
),
);
consume_compute_meter(invoke_context, cost)?;
hasher.hash(bytes);
}
}
hash_result.copy_from_slice(&hasher.result().to_bytes());
Ok(0)
}
);
declare_syscall!(
/// Set return data
SyscallSetReturnData,
@ -2020,6 +1948,75 @@ declare_syscall!(
}
);
declare_syscallhash!(
// Generic Hashing Syscall
SyscallHash,
fn inner_call<H: HasherImpl>(
invoke_context: &mut InvokeContext,
vals_addr: u64,
vals_len: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
let compute_budget = invoke_context.get_compute_budget();
let hash_base_cost = H::get_base_cost(compute_budget);
let hash_byte_cost = H::get_byte_cost(compute_budget);
let hash_max_slices = H::get_max_slices(compute_budget);
if hash_max_slices < vals_len {
ic_msg!(
invoke_context,
"{} Hashing {} sequences in one syscall is over the limit {}",
H::NAME,
vals_len,
hash_max_slices,
);
return Err(SyscallError::TooManySlices.into());
}
consume_compute_meter(invoke_context, hash_base_cost)?;
let hash_result = translate_slice_mut::<u8>(
memory_mapping,
result_addr,
std::mem::size_of::<H::Output>() as u64,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let mut hasher = H::create_hasher();
if vals_len > 0 {
let vals = translate_slice::<&[u8]>(
memory_mapping,
vals_addr,
vals_len,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
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(),
invoke_context.get_check_size(),
)?;
let cost = compute_budget.mem_op_base_cost.max(
hash_byte_cost.saturating_mul(
(val.len() as u64)
.checked_div(2)
.expect("div by non-zero literal"),
),
);
consume_compute_meter(invoke_context, cost)?;
hasher.hash(bytes);
}
}
hash_result.copy_from_slice(hasher.result().as_ref());
Ok(0)
}
);
#[cfg(test)]
#[allow(clippy::arithmetic_side_effects)]
#[allow(clippy::indexing_slicing)]
@ -2042,7 +2039,7 @@ mod tests {
account::{create_account_shared_data_for_test, AccountSharedData},
bpf_loader,
fee_calculator::FeeCalculator,
hash::hashv,
hash::{hashv, HASH_BYTES},
instruction::Instruction,
program::check_type_assumptions,
stable_layout::stable_instruction::StableInstruction,
@ -2705,7 +2702,7 @@ mod tests {
);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
SyscallHash::call::<Sha256Hasher>(
&mut invoke_context,
ro_va,
ro_len,
@ -2720,7 +2717,7 @@ mod tests {
let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
assert_eq!(hash_result, hash_local);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
SyscallHash::call::<Sha256Hasher>(
&mut invoke_context,
ro_va - 1, // AccessViolation
ro_len,
@ -2732,7 +2729,7 @@ mod tests {
);
assert_access_violation!(result, ro_va - 1, 32);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
SyscallHash::call::<Sha256Hasher>(
&mut invoke_context,
ro_va,
ro_len + 1, // AccessViolation
@ -2744,7 +2741,7 @@ mod tests {
);
assert_access_violation!(result, ro_va, 48);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
SyscallHash::call::<Sha256Hasher>(
&mut invoke_context,
ro_va,
ro_len,
@ -2756,7 +2753,7 @@ mod tests {
);
assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
let mut result = ProgramResult::Ok(0);
SyscallSha256::call(
SyscallHash::call::<Sha256Hasher>(
&mut invoke_context,
ro_va,
ro_len,