From 4d891043d122db12d34204dd35d7fc34624d0c1c Mon Sep 17 00:00:00 2001 From: Dmitri Makarov Date: Wed, 26 Jan 2022 18:26:53 -0800 Subject: [PATCH] Update syscall base costs --- program-runtime/src/compute_budget.rs | 3 + programs/bpf/tests/programs.rs | 22 ++--- programs/bpf_loader/src/syscalls.rs | 132 +++++++++++++++++--------- sdk/src/feature_set.rs | 5 + 4 files changed, 108 insertions(+), 54 deletions(-) diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 0e8290f1b3..9fcb965d32 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -60,6 +60,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 { @@ -88,6 +90,7 @@ impl ComputeBudget { syscall_base_cost: 100, heap_size: None, heap_cost: 8, + mem_op_base_cost: 10, } } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 52ac3492a0..69e6ea01be 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1380,18 +1380,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")] @@ -1403,14 +1403,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", 9128), + ("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 44c0cd654a..332a74b70a 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -24,7 +24,7 @@ use { blake3_syscall_enabled, disable_fees_sysvar, do_support_realloc, libsecp256k1_0_5_upgrade_enabled, prevent_calling_precompiles_as_programs, return_data_syscall_enabled, secp256k1_recover_syscall_enabled, - sol_log_data_syscall_enabled, + sol_log_data_syscall_enabled, update_syscall_base_costs, }, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, @@ -41,7 +41,7 @@ use { }, std::{ alloc::Layout, - cell::{RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, mem::{align_of, size_of}, rc::Rc, slice::from_raw_parts_mut, @@ -574,8 +574,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 .get_loader() @@ -613,7 +617,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 @@ -694,7 +709,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(), @@ -972,9 +995,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 ); @@ -1004,13 +1029,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); } } @@ -1204,9 +1224,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 ); @@ -1241,13 +1263,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); } } @@ -1261,6 +1279,24 @@ fn check_overlapping(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>>, @@ -1287,8 +1323,22 @@ impl<'a, 'b> SyscallObject for SyscallMemcpy<'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); + // 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); + } + + 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 @@ -1331,8 +1381,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 @@ -1375,8 +1424,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 @@ -1432,8 +1480,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 @@ -1576,9 +1623,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 ); @@ -1613,13 +1662,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); } } @@ -3078,7 +3124,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 @@ -3464,7 +3510,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/feature_set.rs b/sdk/src/feature_set.rs index ca85ff49f0..dc6a70484e 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -295,6 +295,10 @@ pub mod spl_associated_token_account_v1_0_4 { solana_sdk::declare_id!("FaTa4SpiaSNH44PGC4z8bnGVTkSRYaWvrBs3KTu8XQQq"); } +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 = [ @@ -363,6 +367,7 @@ lazy_static! { (require_rent_exempt_accounts::id(), "require all new transaction accounts with data to be rent-exempt"), (vote_withdraw_authority_may_change_authorized_voter::id(), "vote account withdraw authority may change the authorized voter #22521"), (spl_associated_token_account_v1_0_4::id(), "SPL Associated Token Account Program release version 1.0.4, tied to token 3.3.0 #22648"), + (update_syscall_base_costs::id(), "Update syscall base costs"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()