pass feature_set to BorrowedAccount (#34542)

Co-authored-by: HaoranYi <haoran.yi@solana.com>
This commit is contained in:
HaoranYi 2023-12-21 13:03:17 -06:00 committed by GitHub
parent 3af306e072
commit 531d69fd10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 540 additions and 269 deletions

View File

@ -571,6 +571,7 @@ pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) {
.get_current_instruction_context()
.unwrap(),
true, // copy_account_data
&invoke_context.feature_set,
)
.unwrap();

View File

@ -410,7 +410,7 @@ impl<'a> InvokeContext<'a> {
})?;
let borrowed_program_account = instruction_context
.try_borrow_instruction_account(self.transaction_context, program_account_index)?;
if !borrowed_program_account.is_executable() {
if !borrowed_program_account.is_executable(&self.feature_set) {
ic_msg!(self, "Account {} is not executable", callee_program_id);
return Err(InstructionError::AccountNotExecutable);
}
@ -821,17 +821,17 @@ mod tests {
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
MockInstruction::ModifyOwned => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data_from_slice(&[1])?,
.set_data_from_slice(&[1], &invoke_context.feature_set)?,
MockInstruction::ModifyNotOwned => instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data_from_slice(&[1])?,
.set_data_from_slice(&[1], &invoke_context.feature_set)?,
MockInstruction::ModifyReadonly => instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.set_data_from_slice(&[1])?,
.set_data_from_slice(&[1], &invoke_context.feature_set)?,
MockInstruction::UnbalancedPush => {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?;
.checked_add_lamports(1, &invoke_context.feature_set)?;
let program_id = *transaction_context.get_key_of_account_at_index(3)?;
let metas = vec![
AccountMeta::new_readonly(
@ -862,7 +862,7 @@ mod tests {
}
MockInstruction::UnbalancedPop => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?,
.checked_add_lamports(1, &invoke_context.feature_set)?,
MockInstruction::ConsumeComputeUnits {
compute_units_to_consume,
desired_result,
@ -874,7 +874,7 @@ mod tests {
}
MockInstruction::Resize { new_len } => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data(vec![0; new_len as usize])?,
.set_data(vec![0; new_len as usize], &invoke_context.feature_set)?,
}
} else {
return Err(InstructionError::InvalidInstructionData);

View File

@ -228,16 +228,16 @@ mod tests {
MockSystemInstruction::TransferLamports { lamports } => {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_sub_lamports(lamports)?;
.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.checked_add_lamports(lamports)?;
.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
MockSystemInstruction::ChangeData { data } => {
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data(vec![data])?;
.set_data(vec![data], &invoke_context.feature_set)?;
Ok(())
}
}
@ -457,14 +457,14 @@ mod tests {
MockSystemInstruction::DoWork { lamports, data } => {
let mut dup_account = instruction_context
.try_borrow_instruction_account(transaction_context, 2)?;
dup_account.checked_sub_lamports(lamports)?;
to_account.checked_add_lamports(lamports)?;
dup_account.set_data(vec![data])?;
dup_account.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
to_account.checked_add_lamports(lamports, &invoke_context.feature_set)?;
dup_account.set_data(vec![data], &invoke_context.feature_set)?;
drop(dup_account);
let mut from_account = instruction_context
.try_borrow_instruction_account(transaction_context, 0)?;
from_account.checked_sub_lamports(lamports)?;
to_account.checked_add_lamports(lamports)?;
from_account.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
to_account.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
}

View File

@ -130,6 +130,7 @@ pub fn invoke_builtin_function(
.transaction_context
.get_current_instruction_context()?,
true, // copy_account_data // There is no VM so direct mapping can not be implemented here
&invoke_context.feature_set,
)?;
// Deserialize data back into instruction params
@ -160,18 +161,25 @@ pub fn invoke_builtin_function(
if borrowed_account.is_writable() {
if let Some(account_info) = account_info_map.get(borrowed_account.get_key()) {
if borrowed_account.get_lamports() != account_info.lamports() {
borrowed_account.set_lamports(account_info.lamports())?;
borrowed_account
.set_lamports(account_info.lamports(), &invoke_context.feature_set)?;
}
if borrowed_account
.can_data_be_resized(account_info.data_len())
.is_ok()
&& borrowed_account.can_data_be_changed().is_ok()
&& borrowed_account
.can_data_be_changed(&invoke_context.feature_set)
.is_ok()
{
borrowed_account.set_data_from_slice(&account_info.data.borrow())?;
borrowed_account.set_data_from_slice(
&account_info.data.borrow(),
&invoke_context.feature_set,
)?;
}
if borrowed_account.get_owner() != account_info.owner {
borrowed_account.set_owner(account_info.owner.as_ref())?;
borrowed_account
.set_owner(account_info.owner.as_ref(), &invoke_context.feature_set)?;
}
}
}
@ -282,17 +290,17 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.unwrap();
if borrowed_account.get_lamports() != account_info.lamports() {
borrowed_account
.set_lamports(account_info.lamports())
.set_lamports(account_info.lamports(), &invoke_context.feature_set)
.unwrap();
}
let account_info_data = account_info.try_borrow_data().unwrap();
// The redundant check helps to avoid the expensive data comparison if we can
match borrowed_account
.can_data_be_resized(account_info_data.len())
.and_then(|_| borrowed_account.can_data_be_changed())
.and_then(|_| borrowed_account.can_data_be_changed(&invoke_context.feature_set))
{
Ok(()) => borrowed_account
.set_data_from_slice(&account_info_data)
.set_data_from_slice(&account_info_data, &invoke_context.feature_set)
.unwrap(),
Err(err) if borrowed_account.get_data() != *account_info_data => {
panic!("{err:?}");
@ -302,7 +310,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
// Change the owner at the end so that we are allowed to change the lamports and data before
if borrowed_account.get_owner() != account_info.owner {
borrowed_account
.set_owner(account_info.owner.as_ref())
.set_owner(account_info.owner.as_ref(), &invoke_context.feature_set)
.unwrap();
}
if instruction_account.is_writable {

View File

@ -162,9 +162,10 @@ impl Processor {
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut lookup_table_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
lookup_table_account.set_state(&ProgramState::LookupTable(LookupTableMeta::new(
authority_key,
)))?;
lookup_table_account.set_state(
&ProgramState::LookupTable(LookupTableMeta::new(authority_key)),
&invoke_context.feature_set,
)?;
Ok(())
}
@ -213,7 +214,7 @@ impl Processor {
let mut lookup_table_meta = lookup_table.meta;
lookup_table_meta.authority = None;
AddressLookupTable::overwrite_meta_data(
lookup_table_account.get_data_mut()?,
lookup_table_account.get_data_mut(&invoke_context.feature_set)?,
lookup_table_meta,
)?;
@ -305,11 +306,12 @@ impl Processor {
)?;
{
AddressLookupTable::overwrite_meta_data(
lookup_table_account.get_data_mut()?,
lookup_table_account.get_data_mut(&invoke_context.feature_set)?,
lookup_table_meta,
)?;
for new_address in new_addresses {
lookup_table_account.extend_from_slice(new_address.as_ref())?;
lookup_table_account
.extend_from_slice(new_address.as_ref(), &invoke_context.feature_set)?;
}
}
drop(lookup_table_account);
@ -381,7 +383,7 @@ impl Processor {
lookup_table_meta.deactivation_slot = clock.slot;
AddressLookupTable::overwrite_meta_data(
lookup_table_account.get_data_mut()?,
lookup_table_account.get_data_mut(&invoke_context.feature_set)?,
lookup_table_meta,
)?;
@ -456,13 +458,13 @@ impl Processor {
let mut recipient_account =
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
recipient_account.checked_add_lamports(withdrawn_lamports)?;
recipient_account.checked_add_lamports(withdrawn_lamports, &invoke_context.feature_set)?;
drop(recipient_account);
let mut lookup_table_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
lookup_table_account.set_data_length(0)?;
lookup_table_account.set_lamports(0)?;
lookup_table_account.set_data_length(0, &invoke_context.feature_set)?;
lookup_table_account.set_lamports(0, &invoke_context.feature_set)?;
Ok(())
}

View File

@ -7,6 +7,7 @@ use {
solana_sdk::{
account::{Account, AccountSharedData},
bpf_loader, bpf_loader_deprecated,
feature_set::FeatureSet,
pubkey::Pubkey,
sysvar::rent::Rent,
transaction_context::{IndexOfAccount, InstructionAccount, TransactionContext},
@ -126,7 +127,13 @@ fn bench_serialize_unaligned(bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, false).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
false,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}
@ -137,7 +144,13 @@ fn bench_serialize_unaligned_copy_account_data(bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
true,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}
@ -149,7 +162,13 @@ fn bench_serialize_aligned(bencher: &mut Bencher) {
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, false).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
false,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}
@ -161,7 +180,13 @@ fn bench_serialize_aligned_copy_account_data(bencher: &mut Bencher) {
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
true,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}
@ -172,7 +197,13 @@ fn bench_serialize_unaligned_max_accounts(bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, false).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
false,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}
@ -184,6 +215,12 @@ fn bench_serialize_aligned_max_accounts(bencher: &mut Bencher) {
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, false).unwrap();
let _ = serialize_parameters(
&transaction_context,
instruction_context,
false,
&FeatureSet::all_enabled(),
)
.unwrap();
});
}

View File

@ -36,7 +36,7 @@ use {
feature_set::{
bpf_account_data_direct_mapping, enable_bpf_loader_extend_program_ix,
enable_bpf_loader_set_authority_checked_ix, native_programs_consume_cu,
remove_bpf_loader_incorrect_program_id,
remove_bpf_loader_incorrect_program_id, FeatureSet,
},
instruction::{AccountMeta, InstructionError},
loader_instruction::LoaderInstruction,
@ -178,7 +178,7 @@ fn write_program_data(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let data = program.get_data_mut()?;
let data = program.get_data_mut(&invoke_context.feature_set)?;
let write_offset = program_data_offset.saturating_add(bytes.len());
if data.len() < write_offset {
ic_msg!(
@ -448,7 +448,7 @@ pub fn process_instruction_inner(
instruction_context,
first_instruction_account,
)?;
if first_account.is_executable() {
if first_account.is_executable(&invoke_context.feature_set) {
ic_logger_msg!(log_collector, "BPF loader is executable");
return Err(Box::new(InstructionError::IncorrectProgramId));
}
@ -459,7 +459,9 @@ pub fn process_instruction_inner(
instruction_context,
program_account_index,
)?;
if program.is_executable() && !check_loader_id(program.get_owner()) {
if program.is_executable(&invoke_context.feature_set)
&& !check_loader_id(program.get_owner())
{
ic_logger_msg!(
log_collector,
"Executable account not owned by the BPF loader"
@ -505,7 +507,7 @@ pub fn process_instruction_inner(
}
// Program Invocation
if !program_account.is_executable() {
if !program_account.is_executable(&invoke_context.feature_set) {
ic_logger_msg!(log_collector, "Program is not executable");
return Err(Box::new(InstructionError::IncorrectProgramId));
}
@ -563,9 +565,12 @@ fn process_loader_upgradeable_instruction(
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?);
buffer.set_state(&UpgradeableLoaderState::Buffer {
authority_address: authority_key,
})?;
buffer.set_state(
&UpgradeableLoaderState::Buffer {
authority_address: authority_key,
},
&invoke_context.feature_set,
)?;
}
UpgradeableLoaderInstruction::Write { offset, bytes } => {
instruction_context.check_number_of_instruction_accounts(2)?;
@ -689,8 +694,8 @@ fn process_loader_upgradeable_instruction(
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
let mut payer =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
payer.checked_add_lamports(buffer.get_lamports())?;
buffer.set_lamports(0)?;
payer.checked_add_lamports(buffer.get_lamports(), &invoke_context.feature_set)?;
buffer.set_lamports(0, &invoke_context.feature_set)?;
}
let owner_id = *program_id;
@ -744,12 +749,15 @@ fn process_loader_upgradeable_instruction(
{
let mut programdata =
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
programdata.set_state(&UpgradeableLoaderState::ProgramData {
slot: clock.slot,
upgrade_authority_address: authority_key,
})?;
programdata.set_state(
&UpgradeableLoaderState::ProgramData {
slot: clock.slot,
upgrade_authority_address: authority_key,
},
&invoke_context.feature_set,
)?;
let dst_slice = programdata
.get_data_mut()?
.get_data_mut(&invoke_context.feature_set)?
.get_mut(
programdata_data_offset
..programdata_data_offset.saturating_add(buffer_data_len),
@ -762,15 +770,21 @@ fn process_loader_upgradeable_instruction(
.get(buffer_data_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?;
dst_slice.copy_from_slice(src_slice);
buffer.set_data_length(UpgradeableLoaderState::size_of_buffer(0))?;
buffer.set_data_length(
UpgradeableLoaderState::size_of_buffer(0),
&invoke_context.feature_set,
)?;
}
// Update the Program account
let mut program =
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
program.set_state(&UpgradeableLoaderState::Program {
programdata_address: programdata_key,
})?;
program.set_state(
&UpgradeableLoaderState::Program {
programdata_address: programdata_key,
},
&invoke_context.feature_set,
)?;
program.set_executable(true)?;
drop(program);
@ -793,7 +807,7 @@ fn process_loader_upgradeable_instruction(
let program =
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
if !program.is_executable() {
if !program.is_executable(&invoke_context.feature_set) {
ic_logger_msg!(log_collector, "Program account not executable");
return Err(InstructionError::AccountNotExecutable);
}
@ -924,12 +938,15 @@ fn process_loader_upgradeable_instruction(
let mut programdata =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
{
programdata.set_state(&UpgradeableLoaderState::ProgramData {
slot: clock.slot,
upgrade_authority_address: authority_key,
})?;
programdata.set_state(
&UpgradeableLoaderState::ProgramData {
slot: clock.slot,
upgrade_authority_address: authority_key,
},
&invoke_context.feature_set,
)?;
let dst_slice = programdata
.get_data_mut()?
.get_data_mut(&invoke_context.feature_set)?
.get_mut(
programdata_data_offset
..programdata_data_offset.saturating_add(buffer_data_len),
@ -944,7 +961,7 @@ fn process_loader_upgradeable_instruction(
dst_slice.copy_from_slice(src_slice);
}
programdata
.get_data_mut()?
.get_data_mut(&invoke_context.feature_set)?
.get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
.ok_or(InstructionError::AccountDataTooSmall)?
.fill(0);
@ -959,10 +976,14 @@ fn process_loader_upgradeable_instruction(
.get_lamports()
.saturating_add(buffer_lamports)
.saturating_sub(programdata_balance_required),
&invoke_context.feature_set,
)?;
buffer.set_lamports(0, &invoke_context.feature_set)?;
programdata.set_lamports(programdata_balance_required, &invoke_context.feature_set)?;
buffer.set_data_length(
UpgradeableLoaderState::size_of_buffer(0),
&invoke_context.feature_set,
)?;
buffer.set_lamports(0)?;
programdata.set_lamports(programdata_balance_required)?;
buffer.set_data_length(UpgradeableLoaderState::size_of_buffer(0))?;
ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id);
}
@ -998,9 +1019,12 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Buffer authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
account.set_state(&UpgradeableLoaderState::Buffer {
authority_address: new_authority.cloned(),
})?;
account.set_state(
&UpgradeableLoaderState::Buffer {
authority_address: new_authority.cloned(),
},
&invoke_context.feature_set,
)?;
}
UpgradeableLoaderState::ProgramData {
slot,
@ -1018,10 +1042,13 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
account.set_state(&UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: new_authority.cloned(),
})?;
account.set_state(
&UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: new_authority.cloned(),
},
&invoke_context.feature_set,
)?;
}
_ => {
ic_logger_msg!(log_collector, "Account does not support authorities");
@ -1067,9 +1094,12 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "New authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
account.set_state(&UpgradeableLoaderState::Buffer {
authority_address: Some(*new_authority_key),
})?;
account.set_state(
&UpgradeableLoaderState::Buffer {
authority_address: Some(*new_authority_key),
},
&invoke_context.feature_set,
)?;
}
UpgradeableLoaderState::ProgramData {
slot,
@ -1091,10 +1121,13 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "New authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
account.set_state(&UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: Some(*new_authority_key),
})?;
account.set_state(
&UpgradeableLoaderState::ProgramData {
slot,
upgrade_authority_address: Some(*new_authority_key),
},
&invoke_context.feature_set,
)?;
}
_ => {
ic_logger_msg!(log_collector, "Account does not support authorities");
@ -1119,13 +1152,19 @@ fn process_loader_upgradeable_instruction(
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let close_key = *close_account.get_key();
let close_account_state = close_account.get_state()?;
close_account.set_data_length(UpgradeableLoaderState::size_of_uninitialized())?;
close_account.set_data_length(
UpgradeableLoaderState::size_of_uninitialized(),
&invoke_context.feature_set,
)?;
match close_account_state {
UpgradeableLoaderState::Uninitialized => {
let mut recipient_account = instruction_context
.try_borrow_instruction_account(transaction_context, 1)?;
recipient_account.checked_add_lamports(close_account.get_lamports())?;
close_account.set_lamports(0)?;
recipient_account.checked_add_lamports(
close_account.get_lamports(),
&invoke_context.feature_set,
)?;
close_account.set_lamports(0, &invoke_context.feature_set)?;
ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key);
}
@ -1137,6 +1176,7 @@ fn process_loader_upgradeable_instruction(
transaction_context,
instruction_context,
&log_collector,
&invoke_context.feature_set,
)?;
ic_logger_msg!(log_collector, "Closed Buffer {}", close_key);
@ -1183,6 +1223,7 @@ fn process_loader_upgradeable_instruction(
transaction_context,
instruction_context,
&log_collector,
&invoke_context.feature_set,
)?;
let clock = invoke_context.get_sysvar_cache().get_clock()?;
invoke_context.programs_modified_by_tx.replenish(
@ -1340,7 +1381,7 @@ fn process_loader_upgradeable_instruction(
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut programdata_account = instruction_context
.try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
programdata_account.set_data_length(new_len)?;
programdata_account.set_data_length(new_len, &invoke_context.feature_set)?;
let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
@ -1361,10 +1402,13 @@ fn process_loader_upgradeable_instruction(
let mut programdata_account = instruction_context
.try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
programdata_account.set_state(&UpgradeableLoaderState::ProgramData {
slot: clock_slot,
upgrade_authority_address,
})?;
programdata_account.set_state(
&UpgradeableLoaderState::ProgramData {
slot: clock_slot,
upgrade_authority_address,
},
&invoke_context.feature_set,
)?;
ic_logger_msg!(
log_collector,
@ -1382,6 +1426,7 @@ fn common_close_account(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
log_collector: &Option<Rc<RefCell<LogCollector>>>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
if authority_address.is_none() {
ic_logger_msg!(log_collector, "Account is immutable");
@ -1404,9 +1449,10 @@ fn common_close_account(
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let mut recipient_account =
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
recipient_account.checked_add_lamports(close_account.get_lamports())?;
close_account.set_lamports(0)?;
close_account.set_state(&UpgradeableLoaderState::Uninitialized)?;
recipient_account.checked_add_lamports(close_account.get_lamports(), feature_set)?;
close_account.set_lamports(0, feature_set)?;
close_account.set_state(&UpgradeableLoaderState::Uninitialized, feature_set)?;
Ok(())
}
@ -1486,6 +1532,7 @@ fn execute<'a, 'b: 'a>(
invoke_context.transaction_context,
instruction_context,
!direct_mapping,
&invoke_context.feature_set,
)?;
serialize_time.stop();
@ -1566,13 +1613,15 @@ fn execute<'a, 'b: 'a>(
instruction_account_index as IndexOfAccount,
)?;
error = EbpfError::SyscallError(Box::new(if account.is_executable() {
InstructionError::ExecutableDataModified
} else if account.is_writable() {
InstructionError::ExternalAccountDataModified
} else {
InstructionError::ReadonlyDataModified
}));
error = EbpfError::SyscallError(Box::new(
if account.is_executable(&invoke_context.feature_set) {
InstructionError::ExecutableDataModified
} else if account.is_writable() {
InstructionError::ExternalAccountDataModified
} else {
InstructionError::ReadonlyDataModified
},
));
}
}
}
@ -1600,6 +1649,7 @@ fn execute<'a, 'b: 'a>(
copy_account_data,
parameter_bytes,
&invoke_context.get_syscall_context()?.accounts_metadata,
&invoke_context.feature_set,
)
}

View File

@ -11,6 +11,7 @@ use {
solana_sdk::{
bpf_loader_deprecated,
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, NON_DUP_MARKER},
feature_set::FeatureSet,
instruction::InstructionError,
pubkey::Pubkey,
system_instruction::MAX_PERMITTED_DATA_LENGTH,
@ -93,6 +94,7 @@ impl Serializer {
fn write_account(
&mut self,
account: &mut BorrowedAccount<'_>,
feature_set: &FeatureSet,
) -> Result<u64, InstructionError> {
let vm_data_addr = if self.copy_account_data {
let vm_data_addr = self.vaddr.saturating_add(self.buffer.len() as u64);
@ -101,7 +103,7 @@ impl Serializer {
} else {
self.push_region(true);
let vaddr = self.vaddr;
self.push_account_data_region(account)?;
self.push_account_data_region(account, feature_set)?;
vaddr
};
@ -121,7 +123,7 @@ impl Serializer {
.map_err(|_| InstructionError::InvalidArgument)?;
self.region_start += BPF_ALIGN_OF_U128.saturating_sub(align_offset);
// put the realloc padding in its own region
self.push_region(account.can_data_be_changed().is_ok());
self.push_region(account.can_data_be_changed(feature_set).is_ok());
}
}
@ -131,12 +133,13 @@ impl Serializer {
fn push_account_data_region(
&mut self,
account: &mut BorrowedAccount<'_>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
if !account.get_data().is_empty() {
let region = match account_data_region_memory_state(account) {
let region = match account_data_region_memory_state(account, feature_set) {
MemoryState::Readable => MemoryRegion::new_readonly(account.get_data(), self.vaddr),
MemoryState::Writable => {
MemoryRegion::new_writable(account.get_data_mut()?, self.vaddr)
MemoryRegion::new_writable(account.get_data_mut(feature_set)?, self.vaddr)
}
MemoryState::Cow(index_in_transaction) => {
MemoryRegion::new_cow(account.get_data(), self.vaddr, index_in_transaction)
@ -191,6 +194,7 @@ pub fn serialize_parameters(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
copy_account_data: bool,
feature_set: &FeatureSet,
) -> Result<
(
AlignedMemory<HOST_ALIGN>,
@ -239,6 +243,7 @@ pub fn serialize_parameters(
instruction_context.get_instruction_data(),
&program_id,
copy_account_data,
feature_set,
)
} else {
serialize_parameters_aligned(
@ -246,6 +251,7 @@ pub fn serialize_parameters(
instruction_context.get_instruction_data(),
&program_id,
copy_account_data,
feature_set,
)
}
}
@ -256,6 +262,7 @@ pub fn deserialize_parameters(
copy_account_data: bool,
buffer: &[u8],
accounts_metadata: &[SerializedAccountMetadata],
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let is_loader_deprecated = *instruction_context
.try_borrow_last_program_account(transaction_context)?
@ -269,6 +276,7 @@ pub fn deserialize_parameters(
copy_account_data,
buffer,
account_lengths,
feature_set,
)
} else {
deserialize_parameters_aligned(
@ -277,6 +285,7 @@ pub fn deserialize_parameters(
copy_account_data,
buffer,
account_lengths,
feature_set,
)
}
}
@ -286,6 +295,7 @@ fn serialize_parameters_unaligned(
instruction_data: &[u8],
program_id: &Pubkey,
copy_account_data: bool,
feature_set: &FeatureSet,
) -> Result<
(
AlignedMemory<HOST_ALIGN>,
@ -336,9 +346,9 @@ fn serialize_parameters_unaligned(
let vm_key_addr = s.write_all(account.get_key().as_ref());
let vm_lamports_addr = s.write::<u64>(account.get_lamports().to_le());
s.write::<u64>((account.get_data().len() as u64).to_le());
let vm_data_addr = s.write_account(&mut account)?;
let vm_data_addr = s.write_account(&mut account, feature_set)?;
let vm_owner_addr = s.write_all(account.get_owner().as_ref());
s.write::<u8>(account.is_executable() as u8);
s.write::<u8>(account.is_executable(feature_set) as u8);
s.write::<u64>((account.get_rent_epoch()).to_le());
accounts_metadata.push(SerializedAccountMetadata {
original_data_len: account.get_data().len(),
@ -364,6 +374,7 @@ pub fn deserialize_parameters_unaligned<I: IntoIterator<Item = usize>>(
copy_account_data: bool,
buffer: &[u8],
account_lengths: I,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (instruction_account_index, pre_len) in (0..instruction_context
@ -385,7 +396,7 @@ pub fn deserialize_parameters_unaligned<I: IntoIterator<Item = usize>>(
.ok_or(InstructionError::InvalidArgument)?,
);
if borrowed_account.get_lamports() != lamports {
borrowed_account.set_lamports(lamports)?;
borrowed_account.set_lamports(lamports, feature_set)?;
}
start += size_of::<u64>() // lamports
+ size_of::<u64>(); // data length
@ -396,9 +407,9 @@ pub fn deserialize_parameters_unaligned<I: IntoIterator<Item = usize>>(
// The redundant check helps to avoid the expensive data comparison if we can
match borrowed_account
.can_data_be_resized(data.len())
.and_then(|_| borrowed_account.can_data_be_changed())
.and_then(|_| borrowed_account.can_data_be_changed(feature_set))
{
Ok(()) => borrowed_account.set_data_from_slice(data)?,
Ok(()) => borrowed_account.set_data_from_slice(data, feature_set)?,
Err(err) if borrowed_account.get_data() != data => return Err(err),
_ => {}
}
@ -417,6 +428,7 @@ fn serialize_parameters_aligned(
instruction_data: &[u8],
program_id: &Pubkey,
copy_account_data: bool,
feature_set: &FeatureSet,
) -> Result<
(
AlignedMemory<HOST_ALIGN>,
@ -466,13 +478,13 @@ fn serialize_parameters_aligned(
s.write::<u8>(NON_DUP_MARKER);
s.write::<u8>(borrowed_account.is_signer() as u8);
s.write::<u8>(borrowed_account.is_writable() as u8);
s.write::<u8>(borrowed_account.is_executable() as u8);
s.write::<u8>(borrowed_account.is_executable(feature_set) as u8);
s.write_all(&[0u8, 0, 0, 0]);
let vm_key_addr = s.write_all(borrowed_account.get_key().as_ref());
let vm_owner_addr = s.write_all(borrowed_account.get_owner().as_ref());
let vm_lamports_addr = s.write::<u64>(borrowed_account.get_lamports().to_le());
s.write::<u64>((borrowed_account.get_data().len() as u64).to_le());
let vm_data_addr = s.write_account(&mut borrowed_account)?;
let vm_data_addr = s.write_account(&mut borrowed_account, feature_set)?;
s.write::<u64>((borrowed_account.get_rent_epoch()).to_le());
accounts_metadata.push(SerializedAccountMetadata {
original_data_len: borrowed_account.get_data().len(),
@ -503,6 +515,7 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
copy_account_data: bool,
buffer: &[u8],
account_lengths: I,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (instruction_account_index, pre_len) in (0..instruction_context
@ -532,7 +545,7 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
.ok_or(InstructionError::InvalidArgument)?,
);
if borrowed_account.get_lamports() != lamports {
borrowed_account.set_lamports(lamports)?;
borrowed_account.set_lamports(lamports, feature_set)?;
}
start += size_of::<u64>(); // lamports
let post_len = LittleEndian::read_u64(
@ -554,9 +567,9 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
.ok_or(InstructionError::InvalidArgument)?;
match borrowed_account
.can_data_be_resized(post_len)
.and_then(|_| borrowed_account.can_data_be_changed())
.and_then(|_| borrowed_account.can_data_be_changed(feature_set))
{
Ok(()) => borrowed_account.set_data_from_slice(data)?,
Ok(()) => borrowed_account.set_data_from_slice(data, feature_set)?,
Err(err) if borrowed_account.get_data() != data => return Err(err),
_ => {}
}
@ -570,14 +583,14 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
.ok_or(InstructionError::InvalidArgument)?;
match borrowed_account
.can_data_be_resized(post_len)
.and_then(|_| borrowed_account.can_data_be_changed())
.and_then(|_| borrowed_account.can_data_be_changed(feature_set))
{
Ok(()) => {
borrowed_account.set_data_length(post_len)?;
borrowed_account.set_data_length(post_len, feature_set)?;
let allocated_bytes = post_len.saturating_sub(pre_len);
if allocated_bytes > 0 {
borrowed_account
.get_data_mut()?
.get_data_mut(feature_set)?
.get_mut(pre_len..pre_len.saturating_add(allocated_bytes))
.ok_or(InstructionError::InvalidArgument)?
.copy_from_slice(
@ -595,15 +608,18 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
start += size_of::<u64>(); // rent_epoch
if borrowed_account.get_owner().to_bytes() != owner {
// Change the owner at the end so that we are allowed to change the lamports and data before
borrowed_account.set_owner(owner)?;
borrowed_account.set_owner(owner, feature_set)?;
}
}
}
Ok(())
}
pub(crate) fn account_data_region_memory_state(account: &BorrowedAccount<'_>) -> MemoryState {
if account.can_data_be_changed().is_ok() {
pub(crate) fn account_data_region_memory_state(
account: &BorrowedAccount<'_>,
feature_set: &FeatureSet,
) -> MemoryState {
if account.can_data_be_changed(feature_set).is_ok() {
if account.is_shared() {
MemoryState::Cow(account.get_index_in_transaction() as u64)
} else {
@ -728,6 +744,7 @@ mod tests {
invoke_context.transaction_context,
instruction_context,
copy_account_data,
&invoke_context.feature_set,
);
assert_eq!(
serialization_result.as_ref().err(),
@ -882,6 +899,7 @@ mod tests {
invoke_context.transaction_context,
instruction_context,
copy_account_data,
&invoke_context.feature_set,
)
.unwrap();
@ -943,6 +961,7 @@ mod tests {
copy_account_data,
serialized.as_slice(),
&accounts_metadata,
&invoke_context.feature_set,
)
.unwrap();
for (index_in_transaction, (_key, original_account)) in
@ -973,6 +992,7 @@ mod tests {
invoke_context.transaction_context,
instruction_context,
copy_account_data,
&invoke_context.feature_set,
)
.unwrap();
let mut serialized_regions = concat_regions(&regions);
@ -1013,6 +1033,7 @@ mod tests {
copy_account_data,
serialized.as_slice(),
&account_lengths,
&invoke_context.feature_set,
)
.unwrap();
for (index_in_transaction, (_key, original_account)) in

View File

@ -8,7 +8,7 @@ use {
memory_region::{MemoryRegion, MemoryState},
},
solana_sdk::{
feature_set::enable_bpf_loader_set_authority_checked_ix,
feature_set::{enable_bpf_loader_set_authority_checked_ix, FeatureSet},
stable_layout::stable_instruction::StableInstruction,
syscalls::{
MAX_CPI_ACCOUNT_INFOS, MAX_CPI_INSTRUCTION_ACCOUNTS, MAX_CPI_INSTRUCTION_DATA_LEN,
@ -883,7 +883,7 @@ where
.transaction_context
.get_key_of_account_at_index(instruction_account.index_in_transaction)?;
if callee_account.is_executable() {
if callee_account.is_executable(&invoke_context.feature_set) {
// Use the known account
consume_compute_meter(
invoke_context,
@ -1139,6 +1139,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
caller_account,
&callee_account,
is_loader_deprecated,
&invoke_context.feature_set,
)?;
}
}
@ -1179,7 +1180,7 @@ fn update_callee_account(
direct_mapping: bool,
) -> Result<(), Error> {
if callee_account.get_lamports() != *caller_account.lamports {
callee_account.set_lamports(*caller_account.lamports)?;
callee_account.set_lamports(*caller_account.lamports, &invoke_context.feature_set)?;
}
if direct_mapping {
@ -1187,7 +1188,7 @@ fn update_callee_account(
let post_len = *caller_account.ref_to_len_in_vm.get()? as usize;
match callee_account
.can_data_be_resized(post_len)
.and_then(|_| callee_account.can_data_be_changed())
.and_then(|_| callee_account.can_data_be_changed(&invoke_context.feature_set))
{
Ok(()) => {
let realloc_bytes_used = post_len.saturating_sub(caller_account.original_data_len);
@ -1195,7 +1196,7 @@ fn update_callee_account(
if is_loader_deprecated && realloc_bytes_used > 0 {
return Err(InstructionError::InvalidRealloc.into());
}
callee_account.set_data_length(post_len)?;
callee_account.set_data_length(post_len, &invoke_context.feature_set)?;
if realloc_bytes_used > 0 {
let serialized_data = translate_slice::<u8>(
memory_mapping,
@ -1206,7 +1207,7 @@ fn update_callee_account(
invoke_context.get_check_aligned(),
)?;
callee_account
.get_data_mut()?
.get_data_mut(&invoke_context.feature_set)?
.get_mut(caller_account.original_data_len..post_len)
.ok_or(SyscallError::InvalidLength)?
.copy_from_slice(serialized_data);
@ -1221,9 +1222,10 @@ fn update_callee_account(
// The redundant check helps to avoid the expensive data comparison if we can
match callee_account
.can_data_be_resized(caller_account.serialized_data.len())
.and_then(|_| callee_account.can_data_be_changed())
.and_then(|_| callee_account.can_data_be_changed(&invoke_context.feature_set))
{
Ok(()) => callee_account.set_data_from_slice(caller_account.serialized_data)?,
Ok(()) => callee_account
.set_data_from_slice(caller_account.serialized_data, &invoke_context.feature_set)?,
Err(err) if callee_account.get_data() != caller_account.serialized_data => {
return Err(Box::new(err));
}
@ -1233,7 +1235,7 @@ fn update_callee_account(
// Change the owner at the end so that we are allowed to change the lamports and data before
if callee_account.get_owner() != caller_account.owner {
callee_account.set_owner(caller_account.owner.as_ref())?;
callee_account.set_owner(caller_account.owner.as_ref(), &invoke_context.feature_set)?;
}
Ok(())
@ -1244,6 +1246,7 @@ fn update_caller_account_perms(
caller_account: &CallerAccount,
callee_account: &BorrowedAccount<'_>,
is_loader_deprecated: bool,
feature_set: &FeatureSet,
) -> Result<(), Error> {
let CallerAccount {
original_data_len,
@ -1253,9 +1256,10 @@ fn update_caller_account_perms(
let data_region = account_data_region(memory_mapping, *vm_data_addr, *original_data_len)?;
if let Some(region) = data_region {
region
.state
.set(account_data_region_memory_state(callee_account));
region.state.set(account_data_region_memory_state(
callee_account,
feature_set,
));
}
let realloc_region = account_realloc_region(
memory_mapping,
@ -1266,7 +1270,7 @@ fn update_caller_account_perms(
if let Some(region) = realloc_region {
region
.state
.set(if callee_account.can_data_be_changed().is_ok() {
.set(if callee_account.can_data_be_changed(feature_set).is_ok() {
MemoryState::Writable
} else {
MemoryState::Readable
@ -1814,9 +1818,11 @@ mod tests {
let mut callee_account = borrow_instruction_account!(invoke_context, 0);
callee_account.set_lamports(42).unwrap();
callee_account
.set_owner(Pubkey::new_unique().as_ref())
.set_lamports(42, &invoke_context.feature_set)
.unwrap();
callee_account
.set_owner(Pubkey::new_unique().as_ref(), &invoke_context.feature_set)
.unwrap();
update_caller_account(
@ -1885,7 +1891,9 @@ mod tests {
(b"foobazbad".to_vec(), MAX_PERMITTED_DATA_INCREASE - 3),
] {
assert_eq!(caller_account.serialized_data, callee_account.get_data());
callee_account.set_data_from_slice(&new_value).unwrap();
callee_account
.set_data_from_slice(&new_value, &invoke_context.feature_set)
.unwrap();
update_caller_account(
&invoke_context,
@ -1913,7 +1921,10 @@ mod tests {
}
callee_account
.set_data_length(original_data_len + MAX_PERMITTED_DATA_INCREASE)
.set_data_length(
original_data_len + MAX_PERMITTED_DATA_INCREASE,
&invoke_context.feature_set,
)
.unwrap();
update_caller_account(
&invoke_context,
@ -1929,7 +1940,10 @@ mod tests {
assert!(is_zeroed(&data_slice[data_len..]));
callee_account
.set_data_length(original_data_len + MAX_PERMITTED_DATA_INCREASE + 1)
.set_data_length(
original_data_len + MAX_PERMITTED_DATA_INCREASE + 1,
&invoke_context.feature_set,
)
.unwrap();
assert_matches!(
update_caller_account(
@ -1944,9 +1958,11 @@ mod tests {
);
// close the account
callee_account.set_data_length(0).unwrap();
callee_account
.set_owner(system_program::id().as_ref())
.set_data_length(0, &invoke_context.feature_set)
.unwrap();
callee_account
.set_owner(system_program::id().as_ref(), &invoke_context.feature_set)
.unwrap();
update_caller_account(
&invoke_context,
@ -2015,9 +2031,13 @@ mod tests {
(vec![], 0), // check lower bound
] {
if change_ptr {
callee_account.set_data(new_value).unwrap();
callee_account
.set_data(new_value, &invoke_context.feature_set)
.unwrap();
} else {
callee_account.set_data_from_slice(&new_value).unwrap();
callee_account
.set_data_from_slice(&new_value, &invoke_context.feature_set)
.unwrap();
}
update_caller_account(
@ -2087,7 +2107,10 @@ mod tests {
}
callee_account
.set_data_length(original_data_len + MAX_PERMITTED_DATA_INCREASE)
.set_data_length(
original_data_len + MAX_PERMITTED_DATA_INCREASE,
&invoke_context.feature_set,
)
.unwrap();
update_caller_account(
&invoke_context,
@ -2105,7 +2128,10 @@ mod tests {
);
callee_account
.set_data_length(original_data_len + MAX_PERMITTED_DATA_INCREASE + 1)
.set_data_length(
original_data_len + MAX_PERMITTED_DATA_INCREASE + 1,
&invoke_context.feature_set,
)
.unwrap();
assert_matches!(
update_caller_account(
@ -2120,9 +2146,11 @@ mod tests {
);
// close the account
callee_account.set_data_length(0).unwrap();
callee_account
.set_owner(system_program::id().as_ref())
.set_data_length(0, &invoke_context.feature_set)
.unwrap();
callee_account
.set_owner(system_program::id().as_ref(), &invoke_context.feature_set)
.unwrap();
update_caller_account(
&invoke_context,
@ -2465,7 +2493,9 @@ mod tests {
// this is done when a writable account is mapped, and it ensures
// through make_data_mut() that the account is made writable and resized
// with enough padding to hold the realloc padding
callee_account.get_data_mut().unwrap();
callee_account
.get_data_mut(&invoke_context.feature_set)
.unwrap();
let serialized_data = translate_slice_mut::<u8>(
&memory_mapping,

View File

@ -127,7 +127,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
ic_msg!(invoke_context, "instruction data too large");
return Err(InstructionError::InvalidInstructionData);
}
config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
config_account.get_data_mut(&invoke_context.feature_set)?[..data.len()].copy_from_slice(data);
Ok(())
});

View File

@ -248,7 +248,7 @@ pub fn process_instruction_write(
}
let end_offset = (offset as usize).saturating_add(bytes.len());
program
.get_data_mut()?
.get_data_mut(&invoke_context.feature_set)?
.get_mut(
LoaderV4State::program_data_offset().saturating_add(offset as usize)
..LoaderV4State::program_data_offset().saturating_add(end_offset),
@ -326,19 +326,20 @@ pub fn process_instruction_truncate(
return Err(InstructionError::InvalidArgument);
}
let lamports_to_receive = program.get_lamports().saturating_sub(required_lamports);
program.checked_sub_lamports(lamports_to_receive)?;
recipient.checked_add_lamports(lamports_to_receive)?;
program.checked_sub_lamports(lamports_to_receive, &invoke_context.feature_set)?;
recipient.checked_add_lamports(lamports_to_receive, &invoke_context.feature_set)?;
}
std::cmp::Ordering::Equal => {}
}
if new_size == 0 {
program.set_data_length(0)?;
program.set_data_length(0, &invoke_context.feature_set)?;
} else {
program.set_data_length(
LoaderV4State::program_data_offset().saturating_add(new_size as usize),
&invoke_context.feature_set,
)?;
if is_initialization {
let state = get_state_mut(program.get_data_mut()?)?;
let state = get_state_mut(program.get_data_mut(&invoke_context.feature_set)?)?;
state.slot = 0;
state.status = LoaderV4Status::Retracted;
state.authority_address = *authority_address;
@ -433,12 +434,12 @@ pub fn process_instruction_deploy(
let rent = invoke_context.get_sysvar_cache().get_rent()?;
let required_lamports = rent.minimum_balance(source_program.get_data().len());
let transfer_lamports = required_lamports.saturating_sub(program.get_lamports());
program.set_data_from_slice(source_program.get_data())?;
source_program.set_data_length(0)?;
source_program.checked_sub_lamports(transfer_lamports)?;
program.checked_add_lamports(transfer_lamports)?;
program.set_data_from_slice(source_program.get_data(), &invoke_context.feature_set)?;
source_program.set_data_length(0, &invoke_context.feature_set)?;
source_program.checked_sub_lamports(transfer_lamports, &invoke_context.feature_set)?;
program.checked_add_lamports(transfer_lamports, &invoke_context.feature_set)?;
}
let state = get_state_mut(program.get_data_mut()?)?;
let state = get_state_mut(program.get_data_mut(&invoke_context.feature_set)?)?;
state.slot = current_slot;
state.status = LoaderV4Status::Deployed;
@ -486,7 +487,7 @@ pub fn process_instruction_retract(
ic_logger_msg!(log_collector, "Program is not deployed");
return Err(InstructionError::InvalidArgument);
}
let state = get_state_mut(program.get_data_mut()?)?;
let state = get_state_mut(program.get_data_mut(&invoke_context.feature_set)?)?;
state.status = LoaderV4Status::Retracted;
Ok(())
}
@ -516,7 +517,7 @@ pub fn process_instruction_transfer_authority(
ic_logger_msg!(log_collector, "New authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
let state = get_state_mut(program.get_data_mut()?)?;
let state = get_state_mut(program.get_data_mut(&invoke_context.feature_set)?)?;
if let Some(new_authority_address) = new_authority_address {
state.authority_address = new_authority_address;
} else if matches!(state.status, LoaderV4Status::Deployed) {

View File

@ -246,7 +246,8 @@ fn bench_create_vm(bencher: &mut Bencher) {
.transaction_context
.get_current_instruction_context()
.unwrap(),
!direct_mapping, // copy_account_data
!direct_mapping, // copy_account_data,
&invoke_context.feature_set,
)
.unwrap();
@ -281,6 +282,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap(),
!direct_mapping, // copy_account_data
&invoke_context.feature_set,
)
.unwrap();

View File

@ -73,7 +73,13 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
Ok(StakeInstruction::Initialize(authorized, lockup)) => {
let mut me = get_stake_account()?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
initialize(&mut me, &authorized, &lockup, &rent)
initialize(
&mut me,
&authorized,
&lockup,
&rent,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => {
let mut me = get_stake_account()?;
@ -90,6 +96,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
stake_authorize,
&clock,
custodian_pubkey,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::AuthorizeWithSeed(args)) => {
@ -111,6 +118,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
args.stake_authorize,
&clock,
custodian_pubkey,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::DelegateStake) => {
@ -213,6 +221,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
None
},
new_warmup_cooldown_rate_epoch(invoke_context),
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::Deactivate) => {
@ -224,7 +233,13 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
Ok(StakeInstruction::SetLockup(lockup)) => {
let mut me = get_stake_account()?;
let clock = invoke_context.get_sysvar_cache().get_clock()?;
set_lockup(&mut me, &lockup, &signers, &clock)
set_lockup(
&mut me,
&lockup,
&signers,
&clock,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::InitializeChecked) => {
let mut me = get_stake_account()?;
@ -245,7 +260,13 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
};
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
initialize(&mut me, &authorized, &Lockup::default(), &rent)
initialize(
&mut me,
&authorized,
&Lockup::default(),
&rent,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::AuthorizeChecked(stake_authorize)) => {
let mut me = get_stake_account()?;
@ -268,6 +289,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
stake_authorize,
&clock,
custodian_pubkey,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::AuthorizeCheckedWithSeed(args)) => {
@ -296,6 +318,7 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
args.stake_authorize,
&clock,
custodian_pubkey,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::SetLockupChecked(lockup_checked)) => {
@ -309,7 +332,13 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
custodian: custodian_pubkey.cloned(),
};
let clock = invoke_context.get_sysvar_cache().get_clock()?;
set_lockup(&mut me, &lockup, &signers, &clock)
set_lockup(
&mut me,
&lockup,
&signers,
&clock,
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::GetMinimumDelegation) => {
let feature_set = invoke_context.feature_set.as_ref();

View File

@ -478,18 +478,23 @@ pub fn initialize(
authorized: &Authorized,
lockup: &Lockup,
rent: &Rent,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
if stake_account.get_data().len() != StakeStateV2::size_of() {
return Err(InstructionError::InvalidAccountData);
}
if let StakeStateV2::Uninitialized = stake_account.get_state()? {
let rent_exempt_reserve = rent.minimum_balance(stake_account.get_data().len());
if stake_account.get_lamports() >= rent_exempt_reserve {
stake_account.set_state(&StakeStateV2::Initialized(Meta {
rent_exempt_reserve,
authorized: *authorized,
lockup: *lockup,
}))
stake_account.set_state(
&StakeStateV2::Initialized(Meta {
rent_exempt_reserve,
authorized: *authorized,
lockup: *lockup,
}),
feature_set,
)
} else {
Err(InstructionError::InsufficientFunds)
}
@ -508,6 +513,7 @@ pub fn authorize(
stake_authorize: StakeAuthorize,
clock: &Clock,
custodian: Option<&Pubkey>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
match stake_account.get_state()? {
StakeStateV2::Stake(mut meta, stake, stake_flags) => {
@ -517,7 +523,7 @@ pub fn authorize(
stake_authorize,
Some((&meta.lockup, clock, custodian)),
)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags), feature_set)
}
StakeStateV2::Initialized(mut meta) => {
meta.authorized.authorize(
@ -526,7 +532,7 @@ pub fn authorize(
stake_authorize,
Some((&meta.lockup, clock, custodian)),
)?;
stake_account.set_state(&StakeStateV2::Initialized(meta))
stake_account.set_state(&StakeStateV2::Initialized(meta), feature_set)
}
_ => Err(InstructionError::InvalidAccountData),
}
@ -544,6 +550,7 @@ pub fn authorize_with_seed(
stake_authorize: StakeAuthorize,
clock: &Clock,
custodian: Option<&Pubkey>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let mut signers = HashSet::default();
if instruction_context.is_instruction_account_signer(authority_base_index)? {
@ -564,6 +571,7 @@ pub fn authorize_with_seed(
stake_authorize,
clock,
custodian,
feature_set,
)
}
@ -601,7 +609,10 @@ pub fn delegate(
&vote_state?.convert_to_current(),
clock.epoch,
);
stake_account.set_state(&StakeStateV2::Stake(meta, stake, StakeFlags::empty()))
stake_account.set_state(
&StakeStateV2::Stake(meta, stake, StakeFlags::empty()),
feature_set,
)
}
StakeStateV2::Stake(meta, mut stake, stake_flags) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
@ -616,7 +627,7 @@ pub fn delegate(
clock,
stake_history,
)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags), feature_set)
}
_ => Err(InstructionError::InvalidAccountData),
}
@ -672,7 +683,10 @@ pub fn deactivate(
if let StakeStateV2::Stake(meta, mut stake, mut stake_flags) = stake_account.get_state()? {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
deactivate_stake(invoke_context, &mut stake, &mut stake_flags, clock.epoch)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))
stake_account.set_state(
&StakeStateV2::Stake(meta, stake, stake_flags),
&invoke_context.feature_set,
)
} else {
Err(InstructionError::InvalidAccountData)
}
@ -683,15 +697,16 @@ pub fn set_lockup(
lockup: &LockupArgs,
signers: &HashSet<Pubkey>,
clock: &Clock,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
match stake_account.get_state()? {
StakeStateV2::Initialized(mut meta) => {
meta.set_lockup(lockup, signers, clock)?;
stake_account.set_state(&StakeStateV2::Initialized(meta))
stake_account.set_state(&StakeStateV2::Initialized(meta), feature_set)
}
StakeStateV2::Stake(mut meta, stake, stake_flags) => {
meta.set_lockup(lockup, signers, clock)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags), feature_set)
}
_ => Err(InstructionError::InvalidAccountData),
}
@ -800,11 +815,17 @@ pub fn split(
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))?;
stake_account.set_state(
&StakeStateV2::Stake(meta, stake, stake_flags),
&invoke_context.feature_set,
)?;
drop(stake_account);
let mut split = instruction_context
.try_borrow_instruction_account(transaction_context, split_index)?;
split.set_state(&StakeStateV2::Stake(split_meta, split_stake, stake_flags))?;
split.set_state(
&StakeStateV2::Stake(split_meta, split_stake, stake_flags),
&invoke_context.feature_set,
)?;
}
StakeStateV2::Initialized(meta) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
@ -823,7 +844,10 @@ pub fn split(
split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
let mut split = instruction_context
.try_borrow_instruction_account(transaction_context, split_index)?;
split.set_state(&StakeStateV2::Initialized(split_meta))?;
split.set_state(
&StakeStateV2::Initialized(split_meta),
&invoke_context.feature_set,
)?;
}
StakeStateV2::Uninitialized => {
let stake_pubkey = transaction_context.get_key_of_account_at_index(
@ -841,17 +865,17 @@ pub fn split(
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
if lamports == stake_account.get_lamports() {
stake_account.set_state(&StakeStateV2::Uninitialized)?;
stake_account.set_state(&StakeStateV2::Uninitialized, &invoke_context.feature_set)?;
}
drop(stake_account);
let mut split =
instruction_context.try_borrow_instruction_account(transaction_context, split_index)?;
split.checked_add_lamports(lamports)?;
split.checked_add_lamports(lamports, &invoke_context.feature_set)?;
drop(split);
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
stake_account.checked_sub_lamports(lamports)?;
stake_account.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
@ -907,16 +931,16 @@ pub fn merge(
ic_msg!(invoke_context, "Merging stake accounts");
if let Some(merged_state) = stake_merge_kind.merge(invoke_context, source_merge_kind, clock)? {
stake_account.set_state(&merged_state)?;
stake_account.set_state(&merged_state, &invoke_context.feature_set)?;
}
// Source is about to be drained, deinitialize its state
source_account.set_state(&StakeStateV2::Uninitialized)?;
source_account.set_state(&StakeStateV2::Uninitialized, &invoke_context.feature_set)?;
// Drain the source stake account
let lamports = source_account.get_lamports();
source_account.checked_sub_lamports(lamports)?;
stake_account.checked_add_lamports(lamports)?;
source_account.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
stake_account.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
@ -1008,8 +1032,9 @@ pub fn redelegate(
deactivate(invoke_context, stake_account, &clock, signers)?;
// transfer the effective stake to the uninitialized stake account
stake_account.checked_sub_lamports(effective_stake)?;
uninitialized_stake_account.checked_add_lamports(effective_stake)?;
stake_account.checked_sub_lamports(effective_stake, &invoke_context.feature_set)?;
uninitialized_stake_account
.checked_add_lamports(effective_stake, &invoke_context.feature_set)?;
// initialize and schedule `uninitialized_stake_account` for activation
let sysvar_cache = invoke_context.get_sysvar_cache();
@ -1023,16 +1048,19 @@ pub fn redelegate(
&uninitialized_stake_meta,
&invoke_context.feature_set,
)?;
uninitialized_stake_account.set_state(&StakeStateV2::Stake(
uninitialized_stake_meta,
new_stake(
stake_amount,
&vote_pubkey,
&vote_state.convert_to_current(),
clock.epoch,
uninitialized_stake_account.set_state(
&StakeStateV2::Stake(
uninitialized_stake_meta,
new_stake(
stake_amount,
&vote_pubkey,
&vote_state.convert_to_current(),
clock.epoch,
),
StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
),
StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
))?;
&invoke_context.feature_set,
)?;
Ok(())
}
@ -1049,6 +1077,7 @@ pub fn withdraw(
withdraw_authority_index: IndexOfAccount,
custodian_index: Option<IndexOfAccount>,
new_rate_activation_epoch: Option<Epoch>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let withdraw_authority_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context
@ -1133,14 +1162,14 @@ pub fn withdraw(
// Deinitialize state upon zero balance
if lamports == stake_account.get_lamports() {
stake_account.set_state(&StakeStateV2::Uninitialized)?;
stake_account.set_state(&StakeStateV2::Uninitialized, feature_set)?;
}
stake_account.checked_sub_lamports(lamports)?;
stake_account.checked_sub_lamports(lamports, feature_set)?;
drop(stake_account);
let mut to =
instruction_context.try_borrow_instruction_account(transaction_context, to_index)?;
to.checked_add_lamports(lamports)?;
to.checked_add_lamports(lamports, feature_set)?;
Ok(())
}
@ -1188,7 +1217,10 @@ pub(crate) fn deactivate_delinquent(
// voted in the last `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
if eligible_for_deactivate_delinquent(&delinquent_vote_state.epoch_credits, current_epoch) {
deactivate_stake(invoke_context, &mut stake, &mut stake_flags, current_epoch)?;
stake_account.set_state(&StakeStateV2::Stake(meta, stake, stake_flags))
stake_account.set_state(
&StakeStateV2::Stake(meta, stake, stake_flags),
&invoke_context.feature_set,
)
} else {
Err(StakeError::MinimumDelinquentEpochsForDeactivationNotMet.into())
}

View File

@ -56,7 +56,10 @@ pub fn advance_nonce_account(
next_durable_nonce,
invoke_context.lamports_per_signature,
);
account.set_state(&Versions::new(State::Initialized(new_data)))
account.set_state(
&Versions::new(State::Initialized(new_data)),
&invoke_context.feature_set,
)
}
State::Uninitialized => {
ic_msg!(
@ -114,7 +117,10 @@ pub fn withdraw_nonce_account(
);
return Err(SystemError::NonceBlockhashNotExpired.into());
}
from.set_state(&Versions::new(State::Uninitialized))?;
from.set_state(
&Versions::new(State::Uninitialized),
&invoke_context.feature_set,
)?;
} else {
let min_balance = rent.minimum_balance(from.get_data().len());
let amount = checked_add(lamports, min_balance)?;
@ -141,11 +147,11 @@ pub fn withdraw_nonce_account(
return Err(InstructionError::MissingRequiredSignature);
}
from.checked_sub_lamports(lamports)?;
from.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
drop(from);
let mut to = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to.checked_add_lamports(lamports)?;
to.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
@ -184,7 +190,7 @@ pub fn initialize_nonce_account(
invoke_context.lamports_per_signature,
);
let state = State::Initialized(data);
account.set_state(&Versions::new(state))
account.set_state(&Versions::new(state), &invoke_context.feature_set)
}
State::Initialized(_) => {
ic_msg!(
@ -215,7 +221,7 @@ pub fn authorize_nonce_account(
.get_state::<Versions>()?
.authorize(signers, *nonce_authority)
{
Ok(versions) => account.set_state(&versions),
Ok(versions) => account.set_state(&versions, &invoke_context.feature_set),
Err(AuthorizeNonceError::Uninitialized) => {
ic_msg!(
invoke_context,
@ -996,7 +1002,9 @@ mod test {
let mut nonce_account = instruction_context
.try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX)
.unwrap();
nonce_account.checked_sub_lamports(42 * 2).unwrap();
nonce_account
.checked_sub_lamports(42 * 2, &invoke_context.feature_set)
.unwrap();
set_invoke_context_blockhash!(invoke_context, 63);
let authorized = *nonce_account.get_key();
let result =

View File

@ -104,7 +104,7 @@ fn allocate(
return Err(SystemError::InvalidAccountDataLength.into());
}
account.set_data_length(space as usize)?;
account.set_data_length(space as usize, &invoke_context.feature_set)?;
Ok(())
}
@ -126,7 +126,7 @@ fn assign(
return Err(InstructionError::MissingRequiredSignature);
}
account.set_owner(&owner.to_bytes())
account.set_owner(&owner.to_bytes(), &invoke_context.feature_set)
}
fn allocate_and_assign(
@ -203,11 +203,11 @@ fn transfer_verified(
return Err(SystemError::ResultWithNegativeLamports.into());
}
from.checked_sub_lamports(lamports)?;
from.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
drop(from);
let mut to = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to.checked_add_lamports(lamports)?;
to.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
}
@ -481,7 +481,9 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
let nonce_versions: nonce::state::Versions = nonce_account.get_state()?;
match nonce_versions.upgrade() {
None => Err(InstructionError::InvalidArgument),
Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
Some(nonce_versions) => {
nonce_account.set_state(&nonce_versions, &invoke_context.feature_set)
}
}
}
SystemInstruction::Allocate { space } => {

View File

@ -156,22 +156,24 @@ fn set_vote_account_state(
&& (!vote_account
.is_rent_exempt_at_data_length(VoteStateVersions::vote_state_size_of(true))
|| vote_account
.set_data_length(VoteStateVersions::vote_state_size_of(true))
.set_data_length(VoteStateVersions::vote_state_size_of(true), feature_set)
.is_err())
{
// Account cannot be resized to the size of a vote state as it will not be rent exempt, or failed to be
// resized for other reasons. So store the V1_14_11 version.
return vote_account.set_state(&VoteStateVersions::V1_14_11(Box::new(
VoteState1_14_11::from(vote_state),
)));
return vote_account.set_state(
&VoteStateVersions::V1_14_11(Box::new(VoteState1_14_11::from(vote_state))),
feature_set,
);
}
// Vote account is large enough to store the newest version of vote state
vote_account.set_state(&VoteStateVersions::new_current(vote_state))
vote_account.set_state(&VoteStateVersions::new_current(vote_state), feature_set)
// Else when the vote_state_add_vote_latency feature is not enabled, then the V1_14_11 version is stored
} else {
vote_account.set_state(&VoteStateVersions::V1_14_11(Box::new(
VoteState1_14_11::from(vote_state),
)))
vote_account.set_state(
&VoteStateVersions::V1_14_11(Box::new(VoteState1_14_11::from(vote_state))),
feature_set,
)
}
}
@ -1006,11 +1008,11 @@ pub fn withdraw<S: std::hash::BuildHasher>(
}
}
vote_account.checked_sub_lamports(lamports)?;
vote_account.checked_sub_lamports(lamports, feature_set)?;
drop(vote_account);
let mut to_account = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to_account.checked_add_lamports(lamports)?;
to_account.checked_add_lamports(lamports, feature_set)?;
Ok(())
}
@ -1345,7 +1347,7 @@ mod tests {
// Test that when the feature is enabled, if the vote account does have sufficient lamports, the
// new vote state is written out
assert_eq!(
borrowed_account.set_lamports(rent.minimum_balance(VoteState::size_of())),
borrowed_account.set_lamports(rent.minimum_balance(VoteState::size_of()), &feature_set),
Ok(())
);
assert_eq!(

View File

@ -80,7 +80,8 @@ where
return Err(InstructionError::InvalidAccountData);
}
proof_context_account.set_data_from_slice(&context_state_data)?;
proof_context_account
.set_data_from_slice(&context_state_data, &invoke_context.feature_set)?;
}
Ok(())
@ -122,10 +123,13 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(),
let mut destination_account =
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
destination_account.checked_add_lamports(proof_context_account.get_lamports())?;
proof_context_account.set_lamports(0)?;
proof_context_account.set_data_length(0)?;
proof_context_account.set_owner(system_program::id().as_ref())?;
destination_account.checked_add_lamports(
proof_context_account.get_lamports(),
&invoke_context.feature_set,
)?;
proof_context_account.set_lamports(0, &invoke_context.feature_set)?;
proof_context_account.set_data_length(0, &invoke_context.feature_set)?;
proof_context_account.set_owner(system_program::id().as_ref(), &invoke_context.feature_set)?;
Ok(())
}

View File

@ -1063,10 +1063,10 @@ fn test_rent_complex() {
MockInstruction::Deduction => {
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.checked_add_lamports(1)?;
.checked_add_lamports(1, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.checked_sub_lamports(1)?;
.checked_sub_lamports(1, &invoke_context.feature_set)?;
Ok(())
}
}
@ -5985,16 +5985,16 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
let lamports = u64::from_le_bytes(instruction_data.try_into().unwrap());
instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.checked_sub_lamports(lamports)?;
.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.checked_add_lamports(lamports)?;
.checked_add_lamports(lamports, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_sub_lamports(lamports)?;
.checked_sub_lamports(lamports, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.checked_add_lamports(lamports)?;
.checked_add_lamports(lamports, &invoke_context.feature_set)?;
Ok(())
});
@ -6496,7 +6496,7 @@ fn test_same_program_id_uses_unique_executable_accounts() {
let instruction_context = transaction_context.get_current_instruction_context()?;
instruction_context
.try_borrow_program_account(transaction_context, 0)?
.set_data_length(2)
.set_data_length(2, &invoke_context.feature_set)
});
let (genesis_config, mint_keypair) = create_genesis_config(50000);
@ -9464,7 +9464,7 @@ fn test_transfer_sysvar() {
let instruction_context = transaction_context.get_current_instruction_context()?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data(vec![0; 40])?;
.set_data(vec![0; 40], &invoke_context.feature_set)?;
Ok(())
});
@ -10317,10 +10317,10 @@ declare_process_instruction!(MockTransferBuiltin, 1, |invoke_context| {
MockTransferInstruction::Transfer(amount) => {
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.checked_sub_lamports(amount)?;
.checked_sub_lamports(amount, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.checked_add_lamports(amount)?;
.checked_add_lamports(amount, &invoke_context.feature_set)?;
Ok(())
}
}
@ -11087,7 +11087,7 @@ declare_process_instruction!(MockReallocBuiltin, 1, |invoke_context| {
// Set data length
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data_length(new_size)?;
.set_data_length(new_size, &invoke_context.feature_set)?;
// set balance
let current_balance = instruction_context
@ -11098,17 +11098,17 @@ declare_process_instruction!(MockReallocBuiltin, 1, |invoke_context| {
if diff_balance.is_positive() {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_sub_lamports(amount)?;
.checked_sub_lamports(amount, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_lamports(new_balance)?;
.set_lamports(new_balance, &invoke_context.feature_set)?;
} else {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(amount)?;
.checked_add_lamports(amount, &invoke_context.feature_set)?;
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_lamports(new_balance)?;
.set_lamports(new_balance, &invoke_context.feature_set)?;
}
Ok(())
}

View File

@ -18,6 +18,7 @@ use {
use {
crate::{
account::{AccountSharedData, ReadableAccount},
feature_set::FeatureSet,
instruction::InstructionError,
pubkey::Pubkey,
},
@ -739,7 +740,11 @@ impl<'a> BorrowedAccount<'a> {
/// Assignes the owner of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_owner(&mut self, pubkey: &[u8]) -> Result<(), InstructionError> {
pub fn set_owner(
&mut self,
pubkey: &[u8],
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
// Only the owner can assign a new owner
if !self.is_owned_by_current_program() {
return Err(InstructionError::ModifiedProgramId);
@ -749,7 +754,7 @@ impl<'a> BorrowedAccount<'a> {
return Err(InstructionError::ModifiedProgramId);
}
// and only if the account is not executable
if self.is_executable() {
if self.is_executable(feature_set) {
return Err(InstructionError::ModifiedProgramId);
}
// and only if the data is zero-initialized or empty
@ -773,7 +778,11 @@ impl<'a> BorrowedAccount<'a> {
/// Overwrites the number of lamports of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
pub fn set_lamports(
&mut self,
lamports: u64,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
// An account not owned by the program cannot have its balance decrease
if !self.is_owned_by_current_program() && lamports < self.get_lamports() {
return Err(InstructionError::ExternalAccountLamportSpend);
@ -783,7 +792,7 @@ impl<'a> BorrowedAccount<'a> {
return Err(InstructionError::ReadonlyLamportChange);
}
// The balance of executable accounts may not change
if self.is_executable() {
if self.is_executable(feature_set) {
return Err(InstructionError::ExecutableLamportChange);
}
// don't touch the account if the lamports do not change
@ -797,21 +806,31 @@ impl<'a> BorrowedAccount<'a> {
/// Adds lamports to this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
pub fn checked_add_lamports(
&mut self,
lamports: u64,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
self.set_lamports(
self.get_lamports()
.checked_add(lamports)
.ok_or(InstructionError::ArithmeticOverflow)?,
feature_set,
)
}
/// Subtracts lamports from this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
pub fn checked_sub_lamports(
&mut self,
lamports: u64,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
self.set_lamports(
self.get_lamports()
.checked_sub(lamports)
.ok_or(InstructionError::ArithmeticOverflow)?,
feature_set,
)
}
@ -823,8 +842,11 @@ impl<'a> BorrowedAccount<'a> {
/// Returns a writable slice of the account data (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn get_data_mut(&mut self) -> Result<&mut [u8], InstructionError> {
self.can_data_be_changed()?;
pub fn get_data_mut(
&mut self,
feature_set: &FeatureSet,
) -> Result<&mut [u8], InstructionError> {
self.can_data_be_changed(feature_set)?;
self.touch()?;
self.make_data_mut();
Ok(self.account.data_as_mut_slice())
@ -849,9 +871,13 @@ impl<'a> BorrowedAccount<'a> {
not(target_os = "solana"),
any(test, feature = "dev-context-only-utils")
))]
pub fn set_data(&mut self, data: Vec<u8>) -> Result<(), InstructionError> {
pub fn set_data(
&mut self,
data: Vec<u8>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
self.can_data_be_resized(data.len())?;
self.can_data_be_changed()?;
self.can_data_be_changed(feature_set)?;
self.touch()?;
self.update_accounts_resize_delta(data.len())?;
@ -864,14 +890,18 @@ impl<'a> BorrowedAccount<'a> {
/// Call this when you have a slice of data you do not own and want to
/// replace the account data with it.
#[cfg(not(target_os = "solana"))]
pub fn set_data_from_slice(&mut self, data: &[u8]) -> Result<(), InstructionError> {
pub fn set_data_from_slice(
&mut self,
data: &[u8],
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
self.can_data_be_resized(data.len())?;
self.can_data_be_changed()?;
self.can_data_be_changed(feature_set)?;
self.touch()?;
self.update_accounts_resize_delta(data.len())?;
// Calling make_data_mut() here guarantees that set_data_from_slice()
// copies in places, extending the account capacity if necessary but
// never reducing it. This is required as the account migh be directly
// never reducing it. This is required as the account might be directly
// mapped into a MemoryRegion, and therefore reducing capacity would
// leave a hole in the vm address space. After CPI or upon program
// termination, the runtime will zero the extra capacity.
@ -885,9 +915,13 @@ impl<'a> BorrowedAccount<'a> {
///
/// Fills it with zeros at the end if is extended or truncates at the end otherwise.
#[cfg(not(target_os = "solana"))]
pub fn set_data_length(&mut self, new_length: usize) -> Result<(), InstructionError> {
pub fn set_data_length(
&mut self,
new_length: usize,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
self.can_data_be_resized(new_length)?;
self.can_data_be_changed()?;
self.can_data_be_changed(feature_set)?;
// don't touch the account if the length does not change
if self.get_data().len() == new_length {
return Ok(());
@ -900,10 +934,14 @@ impl<'a> BorrowedAccount<'a> {
/// Appends all elements in a slice to the account
#[cfg(not(target_os = "solana"))]
pub fn extend_from_slice(&mut self, data: &[u8]) -> Result<(), InstructionError> {
pub fn extend_from_slice(
&mut self,
data: &[u8],
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let new_len = self.get_data().len().saturating_add(data.len());
self.can_data_be_resized(new_len)?;
self.can_data_be_changed()?;
self.can_data_be_changed(feature_set)?;
if data.is_empty() {
return Ok(());
@ -976,8 +1014,12 @@ impl<'a> BorrowedAccount<'a> {
/// Serializes a state into the account data
#[cfg(not(target_os = "solana"))]
pub fn set_state<T: serde::Serialize>(&mut self, state: &T) -> Result<(), InstructionError> {
let data = self.get_data_mut()?;
pub fn set_state<T: serde::Serialize>(
&mut self,
state: &T,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let data = self.get_data_mut(feature_set)?;
let serialized_size =
bincode::serialized_size(state).map_err(|_| InstructionError::GenericError)?;
if serialized_size > data.len() as u64 {
@ -998,7 +1040,7 @@ impl<'a> BorrowedAccount<'a> {
/// Returns whether this account is executable (transaction wide)
#[inline]
pub fn is_executable(&self) -> bool {
pub fn is_executable(&self, _feature_set: &FeatureSet) -> bool {
self.account.executable()
}
@ -1022,11 +1064,11 @@ impl<'a> BorrowedAccount<'a> {
return Err(InstructionError::ExecutableModified);
}
// one can not clear the executable flag
if self.is_executable() && !is_executable {
if self.account.executable() && !is_executable {
return Err(InstructionError::ExecutableModified);
}
// don't touch the account if the executable flag does not change
if self.is_executable() == is_executable {
if self.account.executable() == is_executable {
return Ok(());
}
self.touch()?;
@ -1077,9 +1119,9 @@ impl<'a> BorrowedAccount<'a> {
/// Returns an error if the account data can not be mutated by the current program
#[cfg(not(target_os = "solana"))]
pub fn can_data_be_changed(&self) -> Result<(), InstructionError> {
pub fn can_data_be_changed(&self, feature_set: &FeatureSet) -> Result<(), InstructionError> {
// Only non-executable accounts data can be changed
if self.is_executable() {
if self.is_executable(feature_set) {
return Err(InstructionError::ExecutableDataModified);
}
// and only if the account is writable