From 2aa113fd8ce6590735dcb63f3ed84029d48f99ab Mon Sep 17 00:00:00 2001 From: Jack May Date: Wed, 15 Dec 2021 14:19:47 -0800 Subject: [PATCH] Update syscall base costs --- programs/bpf/tests/programs.rs | 22 ++--- programs/bpf_loader/src/syscalls.rs | 137 ++++++++++++++++++---------- sdk/src/compute_budget.rs | 3 + sdk/src/feature_set.rs | 5 + 4 files changed, 108 insertions(+), 59 deletions(-) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 40a07790d7..50c9d122b6 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1387,18 +1387,18 @@ fn assert_instruction_count() { { programs.extend_from_slice(&[ ("alloc", 1237), - ("bpf_to_bpf", 96), - ("multiple_static", 52), + ("bpf_to_bpf", 313), + ("multiple_static", 208), ("noop", 5), ("noop++", 5), - ("relative_call", 26), + ("relative_call", 210), ("return_data", 980), - ("sanity", 1255), - ("sanity++", 1260), + ("sanity", 2378), + ("sanity++", 2278), ("secp256k1_recover", 25383), - ("sha", 1328), + ("sha", 1895), ("struct_pass", 108), - ("struct_ret", 28), + ("struct_ret", 122), ]); } #[cfg(feature = "bpf_rust")] @@ -1410,14 +1410,14 @@ fn assert_instruction_count() { ("solana_bpf_rust_dep_crate", 47), ("solana_bpf_rust_external_spend", 507), ("solana_bpf_rust_iter", 824), - ("solana_bpf_rust_many_args", 941), - ("solana_bpf_rust_mem", 3086), + ("solana_bpf_rust_many_args", 1289), + ("solana_bpf_rust_mem", 5997), ("solana_bpf_rust_membuiltins", 3976), ("solana_bpf_rust_noop", 481), ("solana_bpf_rust_param_passing", 146), ("solana_bpf_rust_rand", 488), - ("solana_bpf_rust_sanity", 8455), - ("solana_bpf_rust_secp256k1_recover", 25624), + ("solana_bpf_rust_sanity", 9126), + ("solana_bpf_rust_secp256k1_recover", 25889), ("solana_bpf_rust_sha", 30692), ]); } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 679578e583..de40f1dec7 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -26,6 +26,7 @@ use { fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled, prevent_calling_precompiles_as_programs, return_data_syscall_enabled, secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled, + update_syscall_base_costs, }, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, @@ -42,7 +43,7 @@ use { }, std::{ alloc::Layout, - cell::{RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, mem::{align_of, size_of}, rc::Rc, slice::from_raw_parts_mut, @@ -617,8 +618,12 @@ impl<'a, 'b> SyscallObject for SyscallPanic<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - question_mark!(invoke_context.get_compute_meter().consume(len), result); - + if !invoke_context + .feature_set + .is_active(&update_syscall_base_costs::id()) + { + question_mark!(invoke_context.get_compute_meter().consume(len), result); + } let loader_id = question_mark!( invoke_context .transaction_context @@ -657,7 +662,18 @@ impl<'a, 'b> SyscallObject for SyscallLog<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - question_mark!(invoke_context.get_compute_meter().consume(len), result); + let cost = if invoke_context + .feature_set + .is_active(&update_syscall_base_costs::id()) + { + invoke_context + .get_compute_budget() + .syscall_base_cost + .max(len) + } else { + len + }; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); let loader_id = question_mark!( invoke_context @@ -739,7 +755,15 @@ impl<'a, 'b> SyscallObject for SyscallLogBpfComputeUnits<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - question_mark!(invoke_context.get_compute_meter().consume(0), result); + let cost = if invoke_context + .feature_set + .is_active(&update_syscall_base_costs::id()) + { + invoke_context.get_compute_budget().syscall_base_cost + } else { + 0 + }; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); ic_logger_msg!( invoke_context.get_log_collector(), @@ -1020,9 +1044,11 @@ impl<'a, 'b> SyscallObject for SyscallSha256<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + let compute_budget = invoke_context.get_compute_budget(); question_mark!( - invoke_context.get_compute_meter().consume(base_cost), + invoke_context + .get_compute_meter() + .consume(compute_budget.sha256_base_cost), result ); @@ -1053,13 +1079,8 @@ impl<'a, 'b> SyscallObject for SyscallSha256<'a, 'b> { ), result ); - let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; - question_mark!( - invoke_context - .get_compute_meter() - .consume(byte_cost * (val.len() as u64 / 2)), - result - ); + let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); hasher.hash(bytes); } } @@ -1257,9 +1278,11 @@ impl<'a, 'b> SyscallObject for SyscallKeccak256<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + let compute_budget = invoke_context.get_compute_budget(); question_mark!( - invoke_context.get_compute_meter().consume(base_cost), + invoke_context + .get_compute_meter() + .consume(compute_budget.sha256_base_cost), result ); @@ -1295,13 +1318,9 @@ impl<'a, 'b> SyscallObject for SyscallKeccak256<'a, 'b> { ), result ); - let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; - question_mark!( - invoke_context - .get_compute_meter() - .consume(byte_cost * (val.len() as u64 / 2)), - result - ); + let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + hasher.hash(bytes); } } @@ -1317,6 +1336,24 @@ fn check_overlapping_do_not_use(src_addr: u64, dst_addr: u64, n: u64) -> bool { || (dst_addr <= src_addr && dst_addr + n > src_addr) } +fn mem_op_consume<'a, 'b>( + invoke_context: &Ref<&'a mut InvokeContext<'b>>, + n: u64, +) -> Result<(), EbpfError> { + let compute_budget = invoke_context.get_compute_budget(); + let cost = if invoke_context + .feature_set + .is_active(&update_syscall_base_costs::id()) + { + compute_budget + .mem_op_base_cost + .max(n / compute_budget.cpi_bytes_per_unit) + } else { + n / compute_budget.cpi_bytes_per_unit + }; + invoke_context.get_compute_meter().consume(cost) +} + /// memcpy pub struct SyscallMemcpy<'a, 'b> { invoke_context: Rc>>, @@ -1338,6 +1375,18 @@ impl<'a, 'b> SyscallObject for SyscallMemcpy<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); + // When deprecating `update_syscall_base_costs` switch to `mem_op_consume` + let compute_budget = invoke_context.get_compute_budget(); + let update_syscall_base_costs = invoke_context + .feature_set + .is_active(&update_syscall_base_costs::id()); + if update_syscall_base_costs { + let cost = compute_budget + .mem_op_base_cost + .max(n / compute_budget.cpi_bytes_per_unit); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + } + let use_fixed_nonoverlapping_check = invoke_context .feature_set .is_active(&fixed_memcpy_nonoverlapping_check::id()); @@ -1355,14 +1404,10 @@ impl<'a, 'b> SyscallObject for SyscallMemcpy<'a, 'b> { } } - let invoke_context = question_mark!( - self.invoke_context - .try_borrow() - .map_err(|_| SyscallError::InvokeContextBorrowFailed), - result - ); - let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; - question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + if !update_syscall_base_costs { + let cost = n / compute_budget.cpi_bytes_per_unit; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + }; let loader_id = question_mark!( invoke_context @@ -1406,8 +1451,7 @@ impl<'a, 'b> SyscallObject for SyscallMemmove<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; - question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + question_mark!(mem_op_consume(&invoke_context, n), result); let loader_id = question_mark!( invoke_context @@ -1451,8 +1495,7 @@ impl<'a, 'b> SyscallObject for SyscallMemcmp<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; - question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + question_mark!(mem_op_consume(&invoke_context, n), result); let loader_id = question_mark!( invoke_context @@ -1509,8 +1552,7 @@ impl<'a, 'b> SyscallObject for SyscallMemset<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; - question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + question_mark!(mem_op_consume(&invoke_context, n), result); let loader_id = question_mark!( invoke_context @@ -1844,9 +1886,11 @@ impl<'a, 'b> SyscallObject for SyscallBlake3<'a, 'b> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + let compute_budget = invoke_context.get_compute_budget(); question_mark!( - invoke_context.get_compute_meter().consume(base_cost), + invoke_context + .get_compute_meter() + .consume(compute_budget.sha256_base_cost), result ); @@ -1882,13 +1926,10 @@ impl<'a, 'b> SyscallObject for SyscallBlake3<'a, 'b> { ), result ); - let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; - question_mark!( - invoke_context - .get_compute_meter() - .consume(byte_cost * (val.len() as u64 / 2)), - result - ); + + let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + hasher.hash(bytes); } } @@ -3347,7 +3388,7 @@ mod tests { .borrow_mut() .get_compute_meter() .borrow_mut() - .mock_set_remaining((string.len() as u64 * 5) - 1); + .mock_set_remaining(400 - 1); let mut result: Result> = Ok(0); syscall_sol_log.call( 0x100000001, // AccessViolation @@ -3727,7 +3768,7 @@ mod tests { .borrow_mut() .mock_set_remaining( (invoke_context.get_compute_budget().sha256_base_cost - + (bytes1.len() + bytes2.len()) as u64 + + ((bytes1.len() + bytes2.len()) as u64 / 2) * invoke_context.get_compute_budget().sha256_byte_cost) * 4, ); diff --git a/sdk/src/compute_budget.rs b/sdk/src/compute_budget.rs index b9a5aaa3ce..595939d9a5 100644 --- a/sdk/src/compute_budget.rs +++ b/sdk/src/compute_budget.rs @@ -95,6 +95,8 @@ pub struct ComputeBudget { /// Number of compute units per additional 32k heap above the default (~.5 /// us per 32k at 15 units/us rounded up) pub heap_cost: u64, + /// Memory operation syscall base cost + pub mem_op_base_cost: u64, } impl Default for ComputeBudget { fn default() -> Self { @@ -122,6 +124,7 @@ impl ComputeBudget { zk_token_elgamal_op_cost: 25_000, heap_size: None, heap_cost: 8, + mem_op_base_cost: 15, } } pub fn process_transaction( diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 7879084185..0a8ce93ae0 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -303,6 +303,10 @@ pub mod filter_votes_outside_slot_hashes { solana_sdk::declare_id!("3gtZPqvPpsbXZVCx6hceMfWxtsmrjMzmg8C7PLKSxS2d"); } +pub mod update_syscall_base_costs { + solana_sdk::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -373,6 +377,7 @@ lazy_static! { (max_tx_account_locks::id(), "enforce max number of locked accounts per transaction"), (require_rent_exempt_accounts::id(), "require all new transaction accounts with data to be rent-exempt"), (filter_votes_outside_slot_hashes::id(), "filter vote slots older than the slot hashes history"), + (update_syscall_base_costs::id(), "Update syscall base costs"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()