From 43cbe8d01caa3ae72ed9ebc3136978351041cb58 Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Sat, 2 Sep 2023 16:16:21 +0530 Subject: [PATCH 01/11] updated inner_call for hashing fn to follow generic approach --- programs/bpf_loader/src/syscalls/mod.rs | 362 +++++++++++------------- 1 file changed, 159 insertions(+), 203 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 64d1d85e5ee964..b6c7e496effc8d 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -132,6 +132,66 @@ pub enum SyscallError { type Error = Box; +pub trait HasherImpl { + const HASH_BYTES: usize; + + fn create_hasher() -> Self; + fn hash(&mut self, val: &[u8]); + fn result(self) -> [u8; HASH_BYTES]; +} + +pub struct Sha256Hasher(Hasher); +pub struct Blake3Hasher(blake3::Hasher); +pub struct Keccak256Hasher(keccak::Hasher); + +impl HasherImpl for Sha256Hasher { + const HASH_BYTES: usize = HASH_BYTES; + + fn create_hasher() -> Self { + Sha256Hasher(Hasher::default()) + } + + fn hash(&mut self, val: &[u8]) { + self.0.hash(val); + } + + fn result(self) -> [u8; HASH_BYTES] { + self.0.result().to_bytes() + } +} + +impl HasherImpl for Blake3Hasher { + const HASH_BYTES: usize = blake3::HASH_BYTES; + + fn create_hasher() -> Self { + Blake3Hasher(blake3::Hasher::default()) + } + + fn hash(&mut self, val: &[u8]) { + self.0.hash(val); + } + + fn result(self) -> [u8; HASH_BYTES] { + self.0.result().to_bytes() + } +} + +impl HasherImpl for Keccak256Hasher { + const HASH_BYTES: usize = keccak::HASH_BYTES; + + fn create_hasher() -> Self { + Keccak256Hasher(keccak::Hasher::default()) + } + + fn hash(&mut self, val: &[u8]) { + self.0.hash(val); + } + + fn result(self) -> [u8; HASH_BYTES] { + self.0.result().to_bytes() + } +} + fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> { invoke_context.consume_checked(amount)?; Ok(()) @@ -220,10 +280,10 @@ pub fn create_program_runtime_environment_v1<'a>( )?; // Sha256 - result.register_function_hashed(*b"sol_sha256", SyscallSha256::call)?; + result.register_function(*b"sol_sha256", SyscallHash::call::)?; // Keccak256 - result.register_function_hashed(*b"sol_keccak256", SyscallKeccak256::call)?; + result.register_function(*b"sol_keccak256", SyscallHash::call::)?; // Secp256k1 Recover result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?; @@ -233,7 +293,7 @@ pub fn create_program_runtime_environment_v1<'a>( result, blake3_syscall_enabled, *b"sol_blake3", - SyscallBlake3::call, + SyscallHash::call::, )?; // Elliptic Curve Operations @@ -519,6 +579,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( + 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::( + 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 +836,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 { - 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::( - 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::( - 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 { - 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::( - 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::( - 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 +1270,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 { - 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::( - 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::( - 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, @@ -2018,6 +1909,71 @@ declare_syscall!( _ => Err(SyscallError::InvalidAttribute.into()), } } +) + +declare_syscallhash!( + // Generic Hashing Syscall + SyscallHash, + 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 { + let compute_budget = invoke_context.get_compute_budget(); + if compute_budget.sha256_max_slices < vals_len { + ic_msg!( + invoke_context, + "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::( + memory_mapping, + result_addr, + H::HASH_BYTES 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::( + 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()); + Ok(0) + } ); #[cfg(test)] @@ -2705,7 +2661,7 @@ mod tests { ); let mut result = ProgramResult::Ok(0); - SyscallSha256::call( + SyscallHash::call::( &mut invoke_context, ro_va, ro_len, @@ -2720,7 +2676,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::( &mut invoke_context, ro_va - 1, // AccessViolation ro_len, @@ -2732,7 +2688,7 @@ mod tests { ); assert_access_violation!(result, ro_va - 1, 32); let mut result = ProgramResult::Ok(0); - SyscallSha256::call( + SyscallHash::call::( &mut invoke_context, ro_va, ro_len + 1, // AccessViolation @@ -2744,7 +2700,7 @@ mod tests { ); assert_access_violation!(result, ro_va, 48); let mut result = ProgramResult::Ok(0); - SyscallSha256::call( + SyscallHash::call::( &mut invoke_context, ro_va, ro_len, @@ -2756,7 +2712,7 @@ mod tests { ); assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64); let mut result = ProgramResult::Ok(0); - SyscallSha256::call( + SyscallHash::call::( &mut invoke_context, ro_va, ro_len, From 9356e31669502950fa14f36db0b1b332fa48497d Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Wed, 6 Sep 2023 17:36:50 +0530 Subject: [PATCH 02/11] different hash compute budget values for all digests --- program-runtime/src/compute_budget.rs | 11 +++++- programs/bpf_loader/src/syscalls/mod.rs | 48 +++++++++++++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index f9239224b488a0..9c574f94df09dc 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -51,11 +51,17 @@ pub struct ComputeBudget { pub max_invoke_stack_height: usize, /// Maximum cross-program invocation and instructions per transaction pub max_instruction_trace_length: usize, + /// Base number of compute units consumed to call generalized hash + pub hash_base_cost: u64, /// Base number of compute units consumed to call SHA256 pub sha256_base_cost: u64, + /// Incremental number of units consumed by generalized hash (based on bytes) + pub hash_byte_cost: u64, /// Incremental number of units consumed by SHA256 (based on bytes) pub sha256_byte_cost: u64, - /// Maximum number of slices hashed per syscall + /// Maximum number of slices hashed per syscall for generalized hash + pub hash_max_slices: u64, + /// Maximum number of slices hashed per syscall for sha256 pub sha256_max_slices: u64, /// Maximum SBF to BPF call depth pub max_call_depth: usize, @@ -156,8 +162,11 @@ impl ComputeBudget { invoke_units: 1000, max_invoke_stack_height: 5, max_instruction_trace_length: 64, + hash_base_cost: 85, sha256_base_cost: 85, + hash_byte_cost: 1, sha256_byte_cost: 1, + hash_max_slices: 20_000, sha256_max_slices: 20_000, max_call_depth: 64, stack_frame_size: 4_096, diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index b6c7e496effc8d..ce1af771e89c29 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -134,10 +134,12 @@ type Error = Box; pub trait HasherImpl { const HASH_BYTES: usize; + const NAME: &'static str; fn create_hasher() -> Self; fn hash(&mut self, val: &[u8]); fn result(self) -> [u8; HASH_BYTES]; + fn get_compute_budget() -> ComputeBudget; } pub struct Sha256Hasher(Hasher); @@ -146,6 +148,7 @@ pub struct Keccak256Hasher(keccak::Hasher); impl HasherImpl for Sha256Hasher { const HASH_BYTES: usize = HASH_BYTES; + const NAME: &'static str = "Sha256"; fn create_hasher() -> Self { Sha256Hasher(Hasher::default()) @@ -158,10 +161,21 @@ impl HasherImpl for Sha256Hasher { fn result(self) -> [u8; HASH_BYTES] { self.0.result().to_bytes() } + + fn get_compute_budget() -> ComputeBudget { + let mut compute_budget: ComputeBudget = ComputeBudget::default(); + compute_budget.hash_base_cost = 85; + compute_budget.hash_byte_cost = 1; + compute_budget.hash_max_slices = 20_000; + + compute_budget + } + } impl HasherImpl for Blake3Hasher { const HASH_BYTES: usize = blake3::HASH_BYTES; + const NAME: &'static str = "Blake3"; fn create_hasher() -> Self { Blake3Hasher(blake3::Hasher::default()) @@ -174,10 +188,21 @@ impl HasherImpl for Blake3Hasher { fn result(self) -> [u8; HASH_BYTES] { self.0.result().to_bytes() } + + fn get_compute_budget() -> ComputeBudget { + let mut compute_budget: ComputeBudget = ComputeBudget::default(); + compute_budget.hash_base_cost = 85; + compute_budget.hash_byte_cost = 1; + compute_budget.hash_max_slices = 20_000; + + compute_budget + } + } impl HasherImpl for Keccak256Hasher { const HASH_BYTES: usize = keccak::HASH_BYTES; + const NAME: &'static str = "Keccak256"; fn create_hasher() -> Self { Keccak256Hasher(keccak::Hasher::default()) @@ -190,6 +215,16 @@ impl HasherImpl for Keccak256Hasher { fn result(self) -> [u8; HASH_BYTES] { self.0.result().to_bytes() } + + fn get_compute_budget() -> ComputeBudget { + let mut compute_budget: ComputeBudget = ComputeBudget::default(); + compute_budget.hash_base_cost = 85; + compute_budget.hash_byte_cost = 1; + compute_budget.hash_max_slices = 20_000; + + compute_budget + } + } fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> { @@ -1923,18 +1958,19 @@ declare_syscallhash!( _arg5: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - let compute_budget = invoke_context.get_compute_budget(); - if compute_budget.sha256_max_slices < vals_len { + let compute_budget = H::get_compute_budget(); + if compute_budget.hash_max_slices < vals_len { ic_msg!( invoke_context, - "Hashing {} sequences in one syscall is over the limit {}", + "{} Hashing {} sequences in one syscall is over the limit {}", + H::NAME, vals_len, - compute_budget.sha256_max_slices, + compute_budget.hash_max_slices, ); return Err(SyscallError::TooManySlices.into()); } - consume_compute_meter(invoke_context, compute_budget.sha256_base_cost)?; + consume_compute_meter(invoke_context, compute_budget.hash_base_cost)?; let hash_result = translate_slice_mut::( memory_mapping, @@ -1961,7 +1997,7 @@ declare_syscallhash!( invoke_context.get_check_size(), )?; let cost = compute_budget.mem_op_base_cost.max( - compute_budget.sha256_byte_cost.saturating_mul( + compute_budget.hash_byte_cost.saturating_mul( (val.len() as u64) .checked_div(2) .expect("div by non-zero literal"), From d4df62bf8a2e42f713b87eb3eb98f02945f730ed Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Wed, 6 Sep 2023 18:40:58 +0530 Subject: [PATCH 03/11] fixed conflicts --- programs/bpf_loader/src/syscalls/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index ce1af771e89c29..386c6a648ba636 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -315,10 +315,10 @@ pub fn create_program_runtime_environment_v1<'a>( )?; // Sha256 - result.register_function(*b"sol_sha256", SyscallHash::call::)?; + result.register_function_hashed(*b"sol_sha256", SyscallHash::call::)?; // Keccak256 - result.register_function(*b"sol_keccak256", SyscallHash::call::)?; + result.register_function_hashed(*b"sol_keccak256", SyscallHash::call::)?; // Secp256k1 Recover result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?; From 13124c519e4ea1972570995ad3ba945c06be36f3 Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Thu, 7 Sep 2023 13:18:54 +0530 Subject: [PATCH 04/11] reverted changes to compute_budget.rs and added 3method to trait to get compute budget values --- program-runtime/src/compute_budget.rs | 9 ---- programs/bpf_loader/src/syscalls/mod.rs | 68 ++++++++++++++----------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 9c574f94df09dc..9148f416e1de27 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -51,16 +51,10 @@ pub struct ComputeBudget { pub max_invoke_stack_height: usize, /// Maximum cross-program invocation and instructions per transaction pub max_instruction_trace_length: usize, - /// Base number of compute units consumed to call generalized hash - pub hash_base_cost: u64, /// Base number of compute units consumed to call SHA256 pub sha256_base_cost: u64, - /// Incremental number of units consumed by generalized hash (based on bytes) - pub hash_byte_cost: u64, /// Incremental number of units consumed by SHA256 (based on bytes) pub sha256_byte_cost: u64, - /// Maximum number of slices hashed per syscall for generalized hash - pub hash_max_slices: u64, /// Maximum number of slices hashed per syscall for sha256 pub sha256_max_slices: u64, /// Maximum SBF to BPF call depth @@ -162,11 +156,8 @@ impl ComputeBudget { invoke_units: 1000, max_invoke_stack_height: 5, max_instruction_trace_length: 64, - hash_base_cost: 85, sha256_base_cost: 85, - hash_byte_cost: 1, sha256_byte_cost: 1, - hash_max_slices: 20_000, sha256_max_slices: 20_000, max_call_depth: 64, stack_frame_size: 4_096, diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 386c6a648ba636..385412eb86f95d 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -139,7 +139,9 @@ pub trait HasherImpl { fn create_hasher() -> Self; fn hash(&mut self, val: &[u8]); fn result(self) -> [u8; HASH_BYTES]; - fn get_compute_budget() -> ComputeBudget; + 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); @@ -158,17 +160,18 @@ impl HasherImpl for Sha256Hasher { self.0.hash(val); } - fn result(self) -> [u8; HASH_BYTES] { + fn result(self) -> [u8; Self::HASH_BYTES] { self.0.result().to_bytes() } - fn get_compute_budget() -> ComputeBudget { - let mut compute_budget: ComputeBudget = ComputeBudget::default(); - compute_budget.hash_base_cost = 85; - compute_budget.hash_byte_cost = 1; - compute_budget.hash_max_slices = 20_000; - - compute_budget + 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 } } @@ -185,17 +188,18 @@ impl HasherImpl for Blake3Hasher { self.0.hash(val); } - fn result(self) -> [u8; HASH_BYTES] { + fn result(self) -> [u8; Self::HASH_BYTES]{ self.0.result().to_bytes() } - fn get_compute_budget() -> ComputeBudget { - let mut compute_budget: ComputeBudget = ComputeBudget::default(); - compute_budget.hash_base_cost = 85; - compute_budget.hash_byte_cost = 1; - compute_budget.hash_max_slices = 20_000; - - compute_budget + 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 } } @@ -212,17 +216,18 @@ impl HasherImpl for Keccak256Hasher { self.0.hash(val); } - fn result(self) -> [u8; HASH_BYTES] { + fn result(self) -> [u8; Self::HASH_BYTES] { self.0.result().to_bytes() } - fn get_compute_budget() -> ComputeBudget { - let mut compute_budget: ComputeBudget = ComputeBudget::default(); - compute_budget.hash_base_cost = 85; - compute_budget.hash_byte_cost = 1; - compute_budget.hash_max_slices = 20_000; - - compute_budget + 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 } } @@ -1958,19 +1963,22 @@ declare_syscallhash!( _arg5: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - let compute_budget = H::get_compute_budget(); - if compute_budget.hash_max_slices < vals_len { + 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, - compute_budget.hash_max_slices, + hash_max_slices, ); return Err(SyscallError::TooManySlices.into()); } - consume_compute_meter(invoke_context, compute_budget.hash_base_cost)?; + consume_compute_meter(invoke_context, hash_base_cost)?; let hash_result = translate_slice_mut::( memory_mapping, @@ -1997,7 +2005,7 @@ declare_syscallhash!( invoke_context.get_check_size(), )?; let cost = compute_budget.mem_op_base_cost.max( - compute_budget.hash_byte_cost.saturating_mul( + hash_byte_cost.saturating_mul( (val.len() as u64) .checked_div(2) .expect("div by non-zero literal"), From c90b536e11245e25b155291b827a365e5c2da86d Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Tue, 12 Sep 2023 12:00:26 +0530 Subject: [PATCH 05/11] updated type for result fn for HasherImpl --- programs/bpf_loader/src/syscalls/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 385412eb86f95d..7599dfd6c80ad7 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -135,10 +135,11 @@ type Error = Box; pub trait HasherImpl { const HASH_BYTES: usize; const NAME: &'static str; + type Output: AsRef<[u8]>; fn create_hasher() -> Self; fn hash(&mut self, val: &[u8]); - fn result(self) -> [u8; HASH_BYTES]; + 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; @@ -151,6 +152,7 @@ pub struct Keccak256Hasher(keccak::Hasher); impl HasherImpl for Sha256Hasher { const HASH_BYTES: usize = HASH_BYTES; const NAME: &'static str = "Sha256"; + type Output = [u8; Self::HASH_BYTES]; fn create_hasher() -> Self { Sha256Hasher(Hasher::default()) @@ -160,7 +162,7 @@ impl HasherImpl for Sha256Hasher { self.0.hash(val); } - fn result(self) -> [u8; Self::HASH_BYTES] { + fn result(self) -> Self::Output { self.0.result().to_bytes() } @@ -179,6 +181,7 @@ impl HasherImpl for Sha256Hasher { impl HasherImpl for Blake3Hasher { const HASH_BYTES: usize = blake3::HASH_BYTES; const NAME: &'static str = "Blake3"; + type Output = [u8; Self::HASH_BYTES]; fn create_hasher() -> Self { Blake3Hasher(blake3::Hasher::default()) @@ -188,7 +191,7 @@ impl HasherImpl for Blake3Hasher { self.0.hash(val); } - fn result(self) -> [u8; Self::HASH_BYTES]{ + fn result(self) -> Self::Output { self.0.result().to_bytes() } @@ -207,6 +210,7 @@ impl HasherImpl for Blake3Hasher { impl HasherImpl for Keccak256Hasher { const HASH_BYTES: usize = keccak::HASH_BYTES; const NAME: &'static str = "Keccak256"; + type Output = [u8; Self::HASH_BYTES]; fn create_hasher() -> Self { Keccak256Hasher(keccak::Hasher::default()) @@ -216,7 +220,7 @@ impl HasherImpl for Keccak256Hasher { self.0.hash(val); } - fn result(self) -> [u8; Self::HASH_BYTES] { + fn result(self) -> Self::Output { self.0.result().to_bytes() } @@ -2015,7 +2019,7 @@ declare_syscallhash!( hasher.hash(bytes); } } - hash_result.copy_from_slice(&hasher.result()); + hash_result.copy_from_slice(&hasher.result().as_ref()); Ok(0) } ); From 5b2260d2ced1e869d39b711e473ec936d83735be Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Wed, 13 Sep 2023 11:32:59 +0530 Subject: [PATCH 06/11] using Hash directly in result fn, got rid of HASH_BYTES and removed comment form compute_budget --- program-runtime/src/compute_budget.rs | 2 +- programs/bpf_loader/src/syscalls/mod.rs | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 9148f416e1de27..f9239224b488a0 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -55,7 +55,7 @@ pub struct ComputeBudget { pub sha256_base_cost: u64, /// Incremental number of units consumed by SHA256 (based on bytes) pub sha256_byte_cost: u64, - /// Maximum number of slices hashed per syscall for sha256 + /// Maximum number of slices hashed per syscall pub sha256_max_slices: u64, /// Maximum SBF to BPF call depth pub max_call_depth: usize, diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 7599dfd6c80ad7..040a3404a0fdaa 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -1,3 +1,5 @@ +use solana_sdk::hash; + pub use self::{ cpi::{SyscallInvokeSignedC, SyscallInvokeSignedRust}, logging::{ @@ -133,7 +135,6 @@ pub enum SyscallError { type Error = Box; pub trait HasherImpl { - const HASH_BYTES: usize; const NAME: &'static str; type Output: AsRef<[u8]>; @@ -150,9 +151,8 @@ pub struct Blake3Hasher(blake3::Hasher); pub struct Keccak256Hasher(keccak::Hasher); impl HasherImpl for Sha256Hasher { - const HASH_BYTES: usize = HASH_BYTES; const NAME: &'static str = "Sha256"; - type Output = [u8; Self::HASH_BYTES]; + type Output = hash::Hash; fn create_hasher() -> Self { Sha256Hasher(Hasher::default()) @@ -163,7 +163,7 @@ impl HasherImpl for Sha256Hasher { } fn result(self) -> Self::Output { - self.0.result().to_bytes() + self.0.result() } fn get_base_cost(compute_budget: &ComputeBudget) -> u64 { @@ -179,9 +179,8 @@ impl HasherImpl for Sha256Hasher { } impl HasherImpl for Blake3Hasher { - const HASH_BYTES: usize = blake3::HASH_BYTES; const NAME: &'static str = "Blake3"; - type Output = [u8; Self::HASH_BYTES]; + type Output = blake3::Hash; fn create_hasher() -> Self { Blake3Hasher(blake3::Hasher::default()) @@ -192,7 +191,7 @@ impl HasherImpl for Blake3Hasher { } fn result(self) -> Self::Output { - self.0.result().to_bytes() + self.0.result() } fn get_base_cost(compute_budget: &ComputeBudget) -> u64 { @@ -208,9 +207,8 @@ impl HasherImpl for Blake3Hasher { } impl HasherImpl for Keccak256Hasher { - const HASH_BYTES: usize = keccak::HASH_BYTES; const NAME: &'static str = "Keccak256"; - type Output = [u8; Self::HASH_BYTES]; + type Output = keccak::Hash; fn create_hasher() -> Self { Keccak256Hasher(keccak::Hasher::default()) @@ -221,7 +219,7 @@ impl HasherImpl for Keccak256Hasher { } fn result(self) -> Self::Output { - self.0.result().to_bytes() + self.0.result() } fn get_base_cost(compute_budget: &ComputeBudget) -> u64 { @@ -1987,7 +1985,7 @@ declare_syscallhash!( let hash_result = translate_slice_mut::( memory_mapping, result_addr, - H::HASH_BYTES as u64, + std::mem::size_of::() as u64, invoke_context.get_check_aligned(), invoke_context.get_check_size(), )?; From d42d3793f4051859974ddecd38261d5718b0760b Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Wed, 13 Sep 2023 11:51:19 +0530 Subject: [PATCH 07/11] updated import statement --- programs/bpf_loader/src/syscalls/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 040a3404a0fdaa..24140110f1f409 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -1,5 +1,3 @@ -use solana_sdk::hash; - pub use self::{ cpi::{SyscallInvokeSignedC, SyscallInvokeSignedRust}, logging::{ @@ -45,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::{Hasher, HASH_BYTES, Hash}, instruction::{ AccountMeta, InstructionError, ProcessedSiblingInstruction, TRANSACTION_LEVEL_STACK_HEIGHT, @@ -152,7 +150,7 @@ pub struct Keccak256Hasher(keccak::Hasher); impl HasherImpl for Sha256Hasher { const NAME: &'static str = "Sha256"; - type Output = hash::Hash; + type Output = Hash; fn create_hasher() -> Self { Sha256Hasher(Hasher::default()) From 551fef57f730da35dc759984b320edcc35f4c8d5 Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Thu, 14 Sep 2023 11:27:36 +0530 Subject: [PATCH 08/11] cargo fmt -all --- programs/bpf_loader/src/syscalls/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 24140110f1f409..74c2bcfcd3e24a 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -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::{Hash, Hasher, HASH_BYTES}, instruction::{ AccountMeta, InstructionError, ProcessedSiblingInstruction, TRANSACTION_LEVEL_STACK_HEIGHT, @@ -173,7 +173,6 @@ impl HasherImpl for Sha256Hasher { fn get_max_slices(compute_budget: &ComputeBudget) -> u64 { compute_budget.sha256_max_slices } - } impl HasherImpl for Blake3Hasher { @@ -201,7 +200,6 @@ impl HasherImpl for Blake3Hasher { fn get_max_slices(compute_budget: &ComputeBudget) -> u64 { compute_budget.sha256_max_slices } - } impl HasherImpl for Keccak256Hasher { @@ -229,7 +227,6 @@ impl HasherImpl for Keccak256Hasher { fn get_max_slices(compute_budget: &ComputeBudget) -> u64 { compute_budget.sha256_max_slices } - } fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> { From 4d1dc30c99a5dfb35466cdd25ca066742d60a761 Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Thu, 14 Sep 2023 11:39:21 +0530 Subject: [PATCH 09/11] removed unused import and reference related warning --- programs/bpf_loader/src/syscalls/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 74c2bcfcd3e24a..bccc9b081f9a47 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -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::{Hash, Hasher, HASH_BYTES}, + hash::{Hash, Hasher}, instruction::{ AccountMeta, InstructionError, ProcessedSiblingInstruction, TRANSACTION_LEVEL_STACK_HEIGHT, @@ -2012,7 +2012,7 @@ declare_syscallhash!( hasher.hash(bytes); } } - hash_result.copy_from_slice(&hasher.result().as_ref()); + hash_result.copy_from_slice(hasher.result().as_ref()); Ok(0) } ); @@ -2039,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, From 7c0854dcb7b96662159e6d303a89d33ab2268567 Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Mon, 25 Sep 2023 20:19:59 +0530 Subject: [PATCH 10/11] oops forgot semicolon --- programs/bpf_loader/src/syscalls/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index bccc9b081f9a47..df2ba96669c2db 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -1946,7 +1946,7 @@ declare_syscall!( _ => Err(SyscallError::InvalidAttribute.into()), } } -) +); declare_syscallhash!( // Generic Hashing Syscall From 5ea186534eb3c325d0ee2e76181017f825668b0a Mon Sep 17 00:00:00 2001 From: Sanj Singh Date: Fri, 13 Oct 2023 15:26:29 +0530 Subject: [PATCH 11/11] removed trailing white space --- programs/bpf_loader/src/syscalls/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index df2ba96669c2db..4193b9fcfc97a8 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -1947,7 +1947,7 @@ declare_syscall!( } } ); - + declare_syscallhash!( // Generic Hashing Syscall SyscallHash,