Update syscall base costs

This commit is contained in:
Jack May 2021-12-15 14:19:47 -08:00 committed by Dmitri Makarov
parent 1309a9cea0
commit 2aa113fd8c
4 changed files with 108 additions and 59 deletions

View File

@ -1387,18 +1387,18 @@ fn assert_instruction_count() {
{ {
programs.extend_from_slice(&[ programs.extend_from_slice(&[
("alloc", 1237), ("alloc", 1237),
("bpf_to_bpf", 96), ("bpf_to_bpf", 313),
("multiple_static", 52), ("multiple_static", 208),
("noop", 5), ("noop", 5),
("noop++", 5), ("noop++", 5),
("relative_call", 26), ("relative_call", 210),
("return_data", 980), ("return_data", 980),
("sanity", 1255), ("sanity", 2378),
("sanity++", 1260), ("sanity++", 2278),
("secp256k1_recover", 25383), ("secp256k1_recover", 25383),
("sha", 1328), ("sha", 1895),
("struct_pass", 108), ("struct_pass", 108),
("struct_ret", 28), ("struct_ret", 122),
]); ]);
} }
#[cfg(feature = "bpf_rust")] #[cfg(feature = "bpf_rust")]
@ -1410,14 +1410,14 @@ fn assert_instruction_count() {
("solana_bpf_rust_dep_crate", 47), ("solana_bpf_rust_dep_crate", 47),
("solana_bpf_rust_external_spend", 507), ("solana_bpf_rust_external_spend", 507),
("solana_bpf_rust_iter", 824), ("solana_bpf_rust_iter", 824),
("solana_bpf_rust_many_args", 941), ("solana_bpf_rust_many_args", 1289),
("solana_bpf_rust_mem", 3086), ("solana_bpf_rust_mem", 5997),
("solana_bpf_rust_membuiltins", 3976), ("solana_bpf_rust_membuiltins", 3976),
("solana_bpf_rust_noop", 481), ("solana_bpf_rust_noop", 481),
("solana_bpf_rust_param_passing", 146), ("solana_bpf_rust_param_passing", 146),
("solana_bpf_rust_rand", 488), ("solana_bpf_rust_rand", 488),
("solana_bpf_rust_sanity", 8455), ("solana_bpf_rust_sanity", 9126),
("solana_bpf_rust_secp256k1_recover", 25624), ("solana_bpf_rust_secp256k1_recover", 25889),
("solana_bpf_rust_sha", 30692), ("solana_bpf_rust_sha", 30692),
]); ]);
} }

View File

@ -26,6 +26,7 @@ use {
fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled, fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled,
prevent_calling_precompiles_as_programs, return_data_syscall_enabled, prevent_calling_precompiles_as_programs, return_data_syscall_enabled,
secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled, secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled,
update_syscall_base_costs,
}, },
hash::{Hasher, HASH_BYTES}, hash::{Hasher, HASH_BYTES},
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
@ -42,7 +43,7 @@ use {
}, },
std::{ std::{
alloc::Layout, alloc::Layout,
cell::{RefCell, RefMut}, cell::{Ref, RefCell, RefMut},
mem::{align_of, size_of}, mem::{align_of, size_of},
rc::Rc, rc::Rc,
slice::from_raw_parts_mut, slice::from_raw_parts_mut,
@ -617,8 +618,12 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallPanic<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
if !invoke_context
.feature_set
.is_active(&update_syscall_base_costs::id())
{
question_mark!(invoke_context.get_compute_meter().consume(len), result); question_mark!(invoke_context.get_compute_meter().consume(len), result);
}
let loader_id = question_mark!( let loader_id = question_mark!(
invoke_context invoke_context
.transaction_context .transaction_context
@ -657,7 +662,18 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLog<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result 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!( let loader_id = question_mark!(
invoke_context invoke_context
@ -739,7 +755,15 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLogBpfComputeUnits<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result 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!( ic_logger_msg!(
invoke_context.get_log_collector(), invoke_context.get_log_collector(),
@ -1020,9 +1044,11 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSha256<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let base_cost = invoke_context.get_compute_budget().sha256_base_cost; let compute_budget = invoke_context.get_compute_budget();
question_mark!( question_mark!(
invoke_context.get_compute_meter().consume(base_cost), invoke_context
.get_compute_meter()
.consume(compute_budget.sha256_base_cost),
result result
); );
@ -1053,13 +1079,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSha256<'a, 'b> {
), ),
result result
); );
let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2);
question_mark!( question_mark!(invoke_context.get_compute_meter().consume(cost), result);
invoke_context
.get_compute_meter()
.consume(byte_cost * (val.len() as u64 / 2)),
result
);
hasher.hash(bytes); hasher.hash(bytes);
} }
} }
@ -1257,9 +1278,11 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallKeccak256<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let base_cost = invoke_context.get_compute_budget().sha256_base_cost; let compute_budget = invoke_context.get_compute_budget();
question_mark!( question_mark!(
invoke_context.get_compute_meter().consume(base_cost), invoke_context
.get_compute_meter()
.consume(compute_budget.sha256_base_cost),
result result
); );
@ -1295,13 +1318,9 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallKeccak256<'a, 'b> {
), ),
result result
); );
let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2);
question_mark!( question_mark!(invoke_context.get_compute_meter().consume(cost), result);
invoke_context
.get_compute_meter()
.consume(byte_cost * (val.len() as u64 / 2)),
result
);
hasher.hash(bytes); 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) || (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<BpfError>> {
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 /// memcpy
pub struct SyscallMemcpy<'a, 'b> { pub struct SyscallMemcpy<'a, 'b> {
invoke_context: Rc<RefCell<&'a mut InvokeContext<'b>>>, invoke_context: Rc<RefCell<&'a mut InvokeContext<'b>>>,
@ -1338,6 +1375,18 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcpy<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result 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 let use_fixed_nonoverlapping_check = invoke_context
.feature_set .feature_set
.is_active(&fixed_memcpy_nonoverlapping_check::id()); .is_active(&fixed_memcpy_nonoverlapping_check::id());
@ -1355,14 +1404,10 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcpy<'a, 'b> {
} }
} }
let invoke_context = question_mark!( if !update_syscall_base_costs {
self.invoke_context let cost = n / compute_budget.cpi_bytes_per_unit;
.try_borrow() question_mark!(invoke_context.get_compute_meter().consume(cost), result);
.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);
let loader_id = question_mark!( let loader_id = question_mark!(
invoke_context invoke_context
@ -1406,8 +1451,7 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemmove<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; question_mark!(mem_op_consume(&invoke_context, n), result);
question_mark!(invoke_context.get_compute_meter().consume(n / cost), result);
let loader_id = question_mark!( let loader_id = question_mark!(
invoke_context invoke_context
@ -1451,8 +1495,7 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcmp<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; question_mark!(mem_op_consume(&invoke_context, n), result);
question_mark!(invoke_context.get_compute_meter().consume(n / cost), result);
let loader_id = question_mark!( let loader_id = question_mark!(
invoke_context invoke_context
@ -1509,8 +1552,7 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemset<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; question_mark!(mem_op_consume(&invoke_context, n), result);
question_mark!(invoke_context.get_compute_meter().consume(n / cost), result);
let loader_id = question_mark!( let loader_id = question_mark!(
invoke_context invoke_context
@ -1844,9 +1886,11 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallBlake3<'a, 'b> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed), .map_err(|_| SyscallError::InvokeContextBorrowFailed),
result result
); );
let base_cost = invoke_context.get_compute_budget().sha256_base_cost; let compute_budget = invoke_context.get_compute_budget();
question_mark!( question_mark!(
invoke_context.get_compute_meter().consume(base_cost), invoke_context
.get_compute_meter()
.consume(compute_budget.sha256_base_cost),
result result
); );
@ -1882,13 +1926,10 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallBlake3<'a, 'b> {
), ),
result result
); );
let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost;
question_mark!( let cost = compute_budget.sha256_byte_cost * (val.len() as u64 / 2);
invoke_context question_mark!(invoke_context.get_compute_meter().consume(cost), result);
.get_compute_meter()
.consume(byte_cost * (val.len() as u64 / 2)),
result
);
hasher.hash(bytes); hasher.hash(bytes);
} }
} }
@ -3347,7 +3388,7 @@ mod tests {
.borrow_mut() .borrow_mut()
.get_compute_meter() .get_compute_meter()
.borrow_mut() .borrow_mut()
.mock_set_remaining((string.len() as u64 * 5) - 1); .mock_set_remaining(400 - 1);
let mut result: Result<u64, EbpfError<BpfError>> = Ok(0); let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
syscall_sol_log.call( syscall_sol_log.call(
0x100000001, // AccessViolation 0x100000001, // AccessViolation
@ -3727,7 +3768,7 @@ mod tests {
.borrow_mut() .borrow_mut()
.mock_set_remaining( .mock_set_remaining(
(invoke_context.get_compute_budget().sha256_base_cost (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) * invoke_context.get_compute_budget().sha256_byte_cost)
* 4, * 4,
); );

View File

@ -95,6 +95,8 @@ pub struct ComputeBudget {
/// Number of compute units per additional 32k heap above the default (~.5 /// Number of compute units per additional 32k heap above the default (~.5
/// us per 32k at 15 units/us rounded up) /// us per 32k at 15 units/us rounded up)
pub heap_cost: u64, pub heap_cost: u64,
/// Memory operation syscall base cost
pub mem_op_base_cost: u64,
} }
impl Default for ComputeBudget { impl Default for ComputeBudget {
fn default() -> Self { fn default() -> Self {
@ -122,6 +124,7 @@ impl ComputeBudget {
zk_token_elgamal_op_cost: 25_000, zk_token_elgamal_op_cost: 25_000,
heap_size: None, heap_size: None,
heap_cost: 8, heap_cost: 8,
mem_op_base_cost: 15,
} }
} }
pub fn process_transaction( pub fn process_transaction(

View File

@ -303,6 +303,10 @@ pub mod filter_votes_outside_slot_hashes {
solana_sdk::declare_id!("3gtZPqvPpsbXZVCx6hceMfWxtsmrjMzmg8C7PLKSxS2d"); solana_sdk::declare_id!("3gtZPqvPpsbXZVCx6hceMfWxtsmrjMzmg8C7PLKSxS2d");
} }
pub mod update_syscall_base_costs {
solana_sdk::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -373,6 +377,7 @@ lazy_static! {
(max_tx_account_locks::id(), "enforce max number of locked accounts per transaction"), (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"), (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"), (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 ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()