Charge compute budget for bytes passed via cpi (#15874)

This commit is contained in:
Jack May 2021-03-15 22:41:44 -07:00 committed by GitHub
parent 8567b41d5f
commit ad9901d7c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 7 deletions

View File

@ -1110,6 +1110,7 @@ mod tests {
stack_frame_size: 4096, stack_frame_size: 4096,
log_pubkey_units: 100, log_pubkey_units: 100,
max_cpi_instruction_size: usize::MAX, max_cpi_instruction_size: usize::MAX,
cpi_bytes_per_unit: 250,
}, },
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
None, None,

View File

@ -16,7 +16,7 @@ use solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState}, bpf_loader_upgradeable::{self, UpgradeableLoaderState},
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{cpi_share_ro_and_exec_accounts, ristretto_mul_syscall_enabled}, feature_set::{cpi_data_cost, cpi_share_ro_and_exec_accounts, ristretto_mul_syscall_enabled},
hash::{Hasher, HASH_BYTES}, hash::{Hasher, HASH_BYTES},
ic_msg, ic_msg,
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
@ -957,7 +957,8 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
let translate = |account_info: &AccountInfo| { let translate = |account_info: &AccountInfo,
invoke_context: &Ref<&mut dyn InvokeContext>| {
// Translate the account from user space // Translate the account from user space
let lamports = { let lamports = {
@ -974,6 +975,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
account_info.owner as *const _ as u64, account_info.owner as *const _ as u64,
self.loader_id, self.loader_id,
)?; )?;
let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = { let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = {
// Double translate data out of RefCell // Double translate data out of RefCell
let data = *translate_type::<&[u8]>( let data = *translate_type::<&[u8]>(
@ -981,6 +983,14 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
account_info.data.as_ptr() as *const _ as u64, account_info.data.as_ptr() as *const _ as u64,
self.loader_id, self.loader_id,
)?; )?;
if invoke_context.is_feature_active(&cpi_data_cost::id()) {
invoke_context.get_compute_meter().consume(
data.len() as u64
/ invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit,
)?;
}
let translated = translate( let translated = translate(
memory_mapping, memory_mapping,
AccessType::Store, AccessType::Store,
@ -1253,7 +1263,8 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
}) })
.collect::<Result<Vec<_>, EbpfError<BpfError>>>()?; .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
let translate = |account_info: &SolAccountInfo| { let translate = |account_info: &SolAccountInfo,
invoke_context: &Ref<&mut dyn InvokeContext>| {
// Translate the account from user space // Translate the account from user space
let lamports = translate_type_mut::<u64>( let lamports = translate_type_mut::<u64>(
@ -1267,6 +1278,14 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
self.loader_id, self.loader_id,
)?; )?;
let vm_data_addr = account_info.data_addr; let vm_data_addr = account_info.data_addr;
if invoke_context.is_feature_active(&cpi_data_cost::id()) {
invoke_context.get_compute_meter().consume(
account_info.data_len
/ invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit,
)?;
}
let data = translate_slice_mut::<u8>( let data = translate_slice_mut::<u8>(
memory_mapping, memory_mapping,
vm_data_addr, vm_data_addr,
@ -1408,7 +1427,7 @@ fn get_translated_accounts<'a, T, F>(
do_translate: F, do_translate: F,
) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>> ) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>>
where where
F: Fn(&T) -> Result<TranslatedAccount<'a>, EbpfError<BpfError>>, F: Fn(&T, &Ref<&mut dyn InvokeContext>) -> Result<TranslatedAccount<'a>, EbpfError<BpfError>>,
{ {
let mut accounts = Vec::with_capacity(account_keys.len()); let mut accounts = Vec::with_capacity(account_keys.len());
let mut refs = Vec::with_capacity(account_keys.len()); let mut refs = Vec::with_capacity(account_keys.len());
@ -1442,7 +1461,7 @@ where
} }
}) })
{ {
let (account, account_ref) = do_translate(account_info)?; let (account, account_ref) = do_translate(account_info, invoke_context)?;
accounts.push(account); accounts.push(account);
refs.push(account_ref); refs.push(account_ref);
} else { } else {

View File

@ -115,6 +115,10 @@ pub mod require_stake_for_gossip {
solana_sdk::declare_id!("6oNzd5Z3M2L1xo4Q5hoox7CR2DuW7m1ETLWH5jHJthwa"); solana_sdk::declare_id!("6oNzd5Z3M2L1xo4Q5hoox7CR2DuW7m1ETLWH5jHJthwa");
} }
pub mod cpi_data_cost {
solana_sdk::declare_id!("Hrg5bXePPGiAVWZfDHbvjqytSeyBDPAGAQ7v6N5i4gCX");
}
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> = [
@ -141,9 +145,10 @@ lazy_static! {
(warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"), (warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"),
(check_init_vote_data::id(), "check initialized Vote data"), (check_init_vote_data::id(), "check initialized Vote data"),
(check_program_owner::id(), "limit programs to operating on accounts owned by itself"), (check_program_owner::id(), "limit programs to operating on accounts owned by itself"),
(cpi_share_ro_and_exec_accounts::id(), "Share RO and Executable accounts during cross-program invocations"), (cpi_share_ro_and_exec_accounts::id(), "share RO and Executable accounts during cross-program invocations"),
(skip_ro_deserialization::id(), "Skip deserialization of read-only accounts"), (skip_ro_deserialization::id(), "skip deserialization of read-only accounts"),
(require_stake_for_gossip::id(), "require stakes for propagating crds values through gossip #15561"), (require_stake_for_gossip::id(), "require stakes for propagating crds values through gossip #15561"),
(cpi_data_cost::id(), "charge the compute budger for data passed via CPI"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()

View File

@ -128,6 +128,8 @@ pub struct BpfComputeBudget {
pub log_pubkey_units: u64, pub log_pubkey_units: u64,
/// Maximum cross-program invocation instruction size /// Maximum cross-program invocation instruction size
pub max_cpi_instruction_size: usize, pub max_cpi_instruction_size: usize,
/// Number of account data bytes per conpute unit charged during a cross-program invocation
pub cpi_bytes_per_unit: u64,
} }
impl Default for BpfComputeBudget { impl Default for BpfComputeBudget {
fn default() -> Self { fn default() -> Self {
@ -149,6 +151,7 @@ impl BpfComputeBudget {
stack_frame_size: 4_096, stack_frame_size: 4_096,
log_pubkey_units: 100, log_pubkey_units: 100,
max_cpi_instruction_size: 1280, // IPv6 Min MTU size max_cpi_instruction_size: 1280, // IPv6 Min MTU size
cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
} }
} }
} }