Allow the same account to be passed multiple times to a single instruction (#7795)

This commit is contained in:
Jack May
2020-01-22 09:11:56 -08:00
committed by GitHub
parent d854e90c23
commit 023074650f
33 changed files with 1392 additions and 765 deletions

View File

@ -77,6 +77,7 @@ mod bpf {
#[cfg(feature = "bpf_rust")]
mod bpf_rust {
use super::*;
use solana_sdk::account::Account;
use solana_sdk::bpf_loader;
use solana_sdk::client::SyncClient;
use solana_sdk::clock::DEFAULT_SLOTS_PER_EPOCH;
@ -142,5 +143,76 @@ mod bpf {
}
}
}
#[test]
fn test_program_bpf_rust_duplicate_accounts() {
solana_logger::setup();
let filename = create_bpf_path("solana_bpf_rust_dup_accounts");
let mut file = File::open(filename).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let bank = Arc::new(Bank::new(&genesis_config));
let bank_client = BankClient::new_shared(&bank);
let program_id = load_program(&bank_client, &mint_keypair, &bpf_loader::id(), elf);
let payee_account = Account::new(10, 1, &program_id);
let payee_pubkey = Pubkey::new_rand();
bank.store_account(&payee_pubkey, &payee_account);
let account = Account::new(10, 1, &program_id);
let pubkey = Pubkey::new_rand();
let account_metas = vec![
AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(payee_pubkey, false),
AccountMeta::new(pubkey, false),
AccountMeta::new(pubkey, false),
];
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
assert!(result.is_ok());
assert_eq!(data[0], 1);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
assert!(result.is_ok());
assert_eq!(data[0], 2);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
assert!(!result.is_ok());
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
let lamports = bank_client.get_balance(&pubkey).unwrap();
assert!(result.is_ok());
assert_eq!(lamports, 11);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
let lamports = bank_client.get_balance(&pubkey).unwrap();
assert!(result.is_ok());
assert_eq!(lamports, 12);
bank.store_account(&pubkey, &account);
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
let result = bank_client.send_instruction(&mint_keypair, instruction);
assert!(!result.is_ok());
}
}
}

View File

@ -8,6 +8,7 @@ use log::*;
use solana_rbpf::{memory_region::MemoryRegion, EbpfVm};
use solana_sdk::{
account::KeyedAccount,
hash::{Hash, Hasher},
instruction::InstructionError,
instruction_processor_utils::{is_executable, limited_deserialize, next_keyed_account},
loader_instruction::LoaderInstruction,
@ -15,6 +16,7 @@ use solana_sdk::{
sysvar::rent,
};
use std::{
collections::HashMap,
convert::TryFrom,
io::{prelude::*, Error},
mem,
@ -48,7 +50,7 @@ pub fn serialize_parameters(
program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
) -> Vec<u8> {
) -> Result<Vec<u8>, InstructionError> {
assert_eq!(32, mem::size_of::<Pubkey>());
let mut v: Vec<u8> = Vec::new();
@ -58,39 +60,84 @@ pub fn serialize_parameters(
v.write_u64::<LittleEndian>(keyed_account.signer_key().is_some() as u64)
.unwrap();
v.write_all(keyed_account.unsigned_key().as_ref()).unwrap();
v.write_u64::<LittleEndian>(keyed_account.account.lamports)
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
.unwrap();
v.write_u64::<LittleEndian>(keyed_account.account.data.len() as u64)
v.write_u64::<LittleEndian>(keyed_account.data_len()? as u64)
.unwrap();
v.write_all(&keyed_account.account.data).unwrap();
v.write_all(keyed_account.account.owner.as_ref()).unwrap();
v.write_all(&keyed_account.try_account_ref()?.data).unwrap();
v.write_all(keyed_account.owner()?.as_ref()).unwrap();
}
v.write_u64::<LittleEndian>(data.len() as u64).unwrap();
v.write_all(data).unwrap();
v.write_all(program_id.as_ref()).unwrap();
v
Ok(v)
}
pub fn deserialize_parameters(keyed_accounts: &mut [KeyedAccount], buffer: &[u8]) {
pub fn deserialize_parameters(
keyed_accounts: &mut [KeyedAccount],
buffer: &[u8],
) -> Result<(), InstructionError> {
assert_eq!(32, mem::size_of::<Pubkey>());
let calculate_hash = |lamports: u64, data: &[u8]| -> Hash {
let mut hasher = Hasher::default();
let mut buf = [0u8; 8];
LittleEndian::write_u64(&mut buf[..], lamports);
hasher.hash(&buf);
hasher.hash(data);
hasher.result()
};
// remember any duplicate accounts
let mut map: HashMap<Pubkey, (Hash, bool)> = HashMap::new();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
if keyed_accounts[i + 1..].contains(keyed_account)
&& !map.contains_key(keyed_account.unsigned_key())
{
let hash = calculate_hash(
keyed_account.lamports()?,
&keyed_account.try_account_ref()?.data,
);
map.insert(*keyed_account.unsigned_key(), (hash, false));
}
}
let mut start = mem::size_of::<u64>();
for keyed_account in keyed_accounts.iter_mut() {
start += mem::size_of::<u64>(); // skip signer_key boolean
start += mem::size_of::<Pubkey>(); // skip pubkey
keyed_account.account.lamports = LittleEndian::read_u64(&buffer[start..]);
start += mem::size_of::<u64>() // signer_key boolean
+ mem::size_of::<Pubkey>(); // pubkey
let lamports = LittleEndian::read_u64(&buffer[start..]);
start += mem::size_of::<u64>() // lamports
+ mem::size_of::<u64>(); // length tag
let end = start + keyed_account.data_len()?;
let data_start = start;
let data_end = end;
start += mem::size_of::<u64>() // skip lamports
+ mem::size_of::<u64>(); // skip length tag
let end = start + keyed_account.account.data.len();
keyed_account
.account
.data
.clone_from_slice(&buffer[start..end]);
// if duplicate, modified, and dirty, then bail
let mut do_update = true;
if let Some((hash, is_dirty)) = map.get_mut(keyed_account.unsigned_key()) {
let new_hash = calculate_hash(lamports, &buffer[data_start..data_end]);
if *hash != new_hash {
if *is_dirty {
return Err(InstructionError::DuplicateAccountOutOfSync);
}
*is_dirty = true; // fail if modified again
} else {
do_update = false; // no changes, don't need to update account
}
}
if do_update {
keyed_account.try_account_ref_mut()?.lamports = lamports;
keyed_account
.try_account_ref_mut()?
.data
.clone_from_slice(&buffer[data_start..data_end]);
}
start += keyed_account.account.data.len() // skip data
+ mem::size_of::<Pubkey>(); // skip owner
start += keyed_account.data_len()? // data
+ mem::size_of::<Pubkey>(); // owner
}
Ok(())
}
pub fn process_instruction(
@ -105,15 +152,11 @@ pub fn process_instruction(
return Err(InstructionError::NotEnoughAccountKeys);
}
if is_executable(keyed_accounts) {
if is_executable(keyed_accounts)? {
let mut keyed_accounts_iter = keyed_accounts.iter_mut();
let program = next_keyed_account(&mut keyed_accounts_iter)?;
if !program.account.executable {
warn!("BPF program account not executable");
return Err(InstructionError::AccountNotExecutable);
}
let (mut vm, heap_region) = match create_vm(&program.account.data) {
let program_account = program.try_account_ref_mut()?;
let (mut vm, heap_region) = match create_vm(&program_account.data) {
Ok(info) => info,
Err(e) => {
warn!("Failed to create BPF VM: {}", e);
@ -122,7 +165,7 @@ pub fn process_instruction(
};
let parameter_accounts = keyed_accounts_iter.into_slice();
let mut parameter_bytes =
serialize_parameters(program_id, parameter_accounts, &instruction_data);
serialize_parameters(program_id, parameter_accounts, &instruction_data)?;
info!("Call BPF program");
match vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) {
@ -143,7 +186,7 @@ pub fn process_instruction(
return Err(InstructionError::GenericError);
}
}
deserialize_parameters(parameter_accounts, &parameter_bytes);
deserialize_parameters(parameter_accounts, &parameter_bytes)?;
info!("BPF program success");
} else if !keyed_accounts.is_empty() {
match limited_deserialize(instruction_data)? {
@ -157,15 +200,11 @@ pub fn process_instruction(
let offset = offset as usize;
let len = bytes.len();
trace!("Write: offset={} length={}", offset, len);
if program.account.data.len() < offset + len {
warn!(
"Write overflow: {} < {}",
program.account.data.len(),
offset + len
);
if program.data_len()? < offset + len {
warn!("Write overflow: {} < {}", program.data_len()?, offset + len);
return Err(InstructionError::AccountDataTooSmall);
}
program.account.data[offset..offset + len].copy_from_slice(&bytes);
program.try_account_ref_mut()?.data[offset..offset + len].copy_from_slice(&bytes);
}
LoaderInstruction::Finalize => {
let mut keyed_accounts_iter = keyed_accounts.iter_mut();
@ -177,14 +216,14 @@ pub fn process_instruction(
return Err(InstructionError::MissingRequiredSignature);
}
if let Err(e) = check_elf(&program.account.data) {
if let Err(e) = check_elf(&program.try_account_ref()?.data) {
warn!("Invalid ELF: {}", e);
return Err(InstructionError::InvalidAccountData);
}
rent::verify_rent_exemption(&program, &rent)?;
program.account.executable = true;
program.try_account_ref_mut()?.executable = true;
info!("Finalize: account {:?}", program.signer_key().unwrap());
}
}
@ -196,8 +235,7 @@ pub fn process_instruction(
mod tests {
use super::*;
use solana_sdk::account::Account;
use std::fs::File;
use std::io::Read;
use std::{cell::RefCell, fs::File, io::Read};
#[test]
#[should_panic(expected = "Error: Exceeded maximum number of instructions allowed")]
@ -221,7 +259,7 @@ mod tests {
fn test_bpf_loader_write() {
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();
let mut program_account = Account::new(1, 0, &program_id);
let mut program_account = Account::new_ref(1, 0, &program_id);
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)];
let instruction_data = bincode::serialize(&LoaderInstruction::Write {
offset: 3,
@ -243,16 +281,19 @@ mod tests {
// Case: Write bytes to an offset
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, true, &mut program_account)];
keyed_accounts[0].account.data = vec![0; 6];
keyed_accounts[0].account.borrow_mut().data = vec![0; 6];
assert_eq!(
Ok(()),
process_instruction(&program_id, &mut keyed_accounts, &instruction_data)
);
assert_eq!(vec![0, 0, 0, 1, 2, 3], keyed_accounts[0].account.data);
assert_eq!(
vec![0, 0, 0, 1, 2, 3],
keyed_accounts[0].account.borrow().data
);
// Case: Overflow
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, true, &mut program_account)];
keyed_accounts[0].account.data = vec![0; 5];
keyed_accounts[0].account.borrow_mut().data = vec![0; 5];
assert_eq!(
Err(InstructionError::AccountDataTooSmall),
process_instruction(&program_id, &mut keyed_accounts, &instruction_data)
@ -268,8 +309,8 @@ mod tests {
let mut elf = Vec::new();
let rent = rent::Rent::default();
file.read_to_end(&mut elf).unwrap();
let mut program_account = Account::new(rent.minimum_balance(elf.len()), 0, &program_id);
program_account.data = elf;
let mut program_account = Account::new_ref(rent.minimum_balance(elf.len()), 0, &program_id);
program_account.borrow_mut().data = elf;
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)];
let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap();
@ -279,7 +320,7 @@ mod tests {
process_instruction(&program_id, &mut vec![], &instruction_data)
);
let mut rent_account = rent::create_account(1, &rent);
let mut rent_account = RefCell::new(rent::create_account(1, &rent));
keyed_accounts.push(KeyedAccount::new(&rent_key, false, &mut rent_account));
// Case: Not signed
@ -297,11 +338,12 @@ mod tests {
Ok(()),
process_instruction(&program_id, &mut keyed_accounts, &instruction_data)
);
assert!(keyed_accounts[0].account.executable);
program_account.executable = false; // Un-finalize the account
assert!(keyed_accounts[0].account.borrow().executable);
program_account.borrow_mut().executable = false; // Un-finalize the account
// Case: Finalize
program_account.data[0] = 0; // bad elf
program_account.borrow_mut().data[0] = 0; // bad elf
let mut keyed_accounts = vec![
KeyedAccount::new(&program_key, true, &mut program_account),
KeyedAccount::new(&rent_key, false, &mut rent_account),
@ -314,6 +356,8 @@ mod tests {
#[test]
fn test_bpf_loader_invoke_main() {
solana_logger::setup();
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();
@ -321,9 +365,9 @@ mod tests {
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
let mut program_account = Account::new(1, 0, &program_id);
program_account.data = elf;
program_account.executable = true;
let mut program_account = Account::new_ref(1, 0, &program_id);
program_account.borrow_mut().data = elf;
program_account.borrow_mut().executable = true;
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)];
@ -340,15 +384,15 @@ mod tests {
);
// Case: Account not executable
keyed_accounts[0].account.executable = false;
keyed_accounts[0].account.borrow_mut().executable = false;
assert_eq!(
Err(InstructionError::InvalidInstructionData),
process_instruction(&program_id, &mut keyed_accounts, &vec![])
);
keyed_accounts[0].account.executable = true;
keyed_accounts[0].account.borrow_mut().executable = true;
// Case: With program and parameter account
let mut parameter_account = Account::new(1, 0, &program_id);
let mut parameter_account = Account::new_ref(1, 0, &program_id);
keyed_accounts.push(KeyedAccount::new(
&program_key,
false,
@ -358,5 +402,15 @@ mod tests {
Ok(()),
process_instruction(&program_id, &mut keyed_accounts, &vec![])
);
// Case: With duplicate accounts
let duplicate_key = Pubkey::new_rand();
let parameter_account = Account::new_ref(1, 0, &program_id);
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
assert_eq!(
Ok(()),
process_instruction(&program_id, &mut keyed_accounts, &vec![])
);
}
}

View File

@ -33,8 +33,8 @@ fn apply_signature(
if let Some(key) = witness_keyed_account.signer_key() {
if &payment.to == key {
budget_state.pending_budget = None;
contract_keyed_account.account.lamports -= payment.lamports;
witness_keyed_account.account.lamports += payment.lamports;
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
witness_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
return Ok(());
}
}
@ -44,8 +44,8 @@ fn apply_signature(
return Err(BudgetError::DestinationMissing.into());
}
budget_state.pending_budget = None;
contract_keyed_account.account.lamports -= payment.lamports;
to_keyed_account.account.lamports += payment.lamports;
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
to_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
}
Ok(())
}
@ -75,8 +75,8 @@ fn apply_timestamp(
return Err(BudgetError::DestinationMissing.into());
}
budget_state.pending_budget = None;
contract_keyed_account.account.lamports -= payment.lamports;
to_keyed_account.account.lamports += payment.lamports;
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
to_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
}
Ok(())
}
@ -93,8 +93,8 @@ fn apply_account_data(
if let Some(ref mut expr) = budget_state.pending_budget {
let key = witness_keyed_account.unsigned_key();
let program_id = witness_keyed_account.account.owner;
let actual_hash = hash(&witness_keyed_account.account.data);
let program_id = witness_keyed_account.owner()?;
let actual_hash = hash(&witness_keyed_account.try_account_ref()?.data);
expr.apply_witness(&Witness::AccountData(actual_hash, program_id), key);
final_payment = expr.final_payment();
}
@ -106,8 +106,8 @@ fn apply_account_data(
return Err(BudgetError::DestinationMissing.into());
}
budget_state.pending_budget = None;
contract_keyed_account.account.lamports -= payment.lamports;
to_keyed_account.account.lamports += payment.lamports;
contract_keyed_account.try_account_ref_mut()?.lamports -= payment.lamports;
to_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
}
Ok(())
}
@ -129,11 +129,12 @@ pub fn process_instruction(
if let Some(payment) = expr.final_payment() {
let to_keyed_account = contract_keyed_account;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
contract_keyed_account.account.lamports = 0;
to_keyed_account.account.lamports += payment.lamports;
contract_keyed_account.try_account_ref_mut()?.lamports = 0;
to_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
return Ok(());
}
let existing = BudgetState::deserialize(&contract_keyed_account.account.data).ok();
let existing =
BudgetState::deserialize(&contract_keyed_account.try_account_ref_mut()?.data).ok();
if Some(true) == existing.map(|x| x.initialized) {
trace!("contract already exists");
return Err(InstructionError::AccountAlreadyInitialized);
@ -141,12 +142,13 @@ pub fn process_instruction(
let mut budget_state = BudgetState::default();
budget_state.pending_budget = Some(*expr);
budget_state.initialized = true;
budget_state.serialize(&mut contract_keyed_account.account.data)
budget_state.serialize(&mut contract_keyed_account.try_account_ref_mut()?.data)
}
BudgetInstruction::ApplyTimestamp(dt) => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut budget_state = BudgetState::deserialize(&contract_keyed_account.account.data)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data)?;
if !budget_state.is_pending() {
return Ok(()); // Nothing to do here.
}
@ -166,12 +168,13 @@ pub fn process_instruction(
dt,
)?;
trace!("apply timestamp committed");
budget_state.serialize(&mut contract_keyed_account.account.data)
budget_state.serialize(&mut contract_keyed_account.try_account_ref_mut()?.data)
}
BudgetInstruction::ApplySignature => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut budget_state = BudgetState::deserialize(&contract_keyed_account.account.data)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data)?;
if !budget_state.is_pending() {
return Ok(()); // Nothing to do here.
}
@ -190,12 +193,13 @@ pub fn process_instruction(
next_keyed_account(keyed_accounts_iter),
)?;
trace!("apply signature committed");
budget_state.serialize(&mut contract_keyed_account.account.data)
budget_state.serialize(&mut contract_keyed_account.try_account_ref_mut()?.data)
}
BudgetInstruction::ApplyAccountData => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut budget_state = BudgetState::deserialize(&contract_keyed_account.account.data)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data)?;
if !budget_state.is_pending() {
return Ok(()); // Nothing to do here.
}
@ -210,7 +214,7 @@ pub fn process_instruction(
next_keyed_account(keyed_accounts_iter),
)?;
trace!("apply account data committed");
budget_state.serialize(&mut contract_keyed_account.account.data)
budget_state.serialize(&mut contract_keyed_account.try_account_ref_mut()?.data)
}
}
}

View File

@ -14,18 +14,20 @@ pub fn process_instruction(
data: &[u8],
) -> Result<(), InstructionError> {
let key_list: ConfigKeys = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
let keyed_accounts_iter = &mut keyed_accounts.iter();
let config_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
let current_data: ConfigKeys =
deserialize(&config_keyed_account.account.data).map_err(|err| {
let current_data: ConfigKeys = {
let config_account = config_keyed_account.try_account_ref_mut()?;
deserialize(&config_account.data).map_err(|err| {
error!(
"Unable to deserialize account[0]: {:?} (len={}): {:?}",
config_keyed_account.account.data,
config_keyed_account.account.data.len(),
config_account.data,
config_account.data.len(),
err
);
InstructionError::InvalidAccountData
})?;
})?
};
let current_signer_keys: Vec<Pubkey> = current_data
.keys
.iter()
@ -89,12 +91,12 @@ pub fn process_instruction(
return Err(InstructionError::MissingRequiredSignature);
}
if config_keyed_account.account.data.len() < data.len() {
if config_keyed_account.data_len()? < data.len() {
error!("instruction data too large");
return Err(InstructionError::InvalidInstructionData);
}
config_keyed_account.account.data[0..data.len()].copy_from_slice(&data);
config_keyed_account.try_account_ref_mut()?.data[0..data.len()].copy_from_slice(&data);
Ok(())
}
@ -109,6 +111,7 @@ mod tests {
signature::{Keypair, KeypairUtil},
system_instruction::SystemInstruction,
};
use std::cell::RefCell;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct MyConfig {
@ -134,7 +137,7 @@ mod tests {
}
}
fn create_config_account(keys: Vec<(Pubkey, bool)>) -> (Keypair, Account) {
fn create_config_account(keys: Vec<(Pubkey, bool)>) -> (Keypair, RefCell<Account>) {
let from_pubkey = Pubkey::new_rand();
let config_keypair = Keypair::new();
let config_pubkey = config_keypair.pubkey();
@ -151,10 +154,10 @@ mod tests {
} => space,
_ => panic!("Not a CreateAccount system instruction"),
};
let mut config_account = Account {
let mut config_account = RefCell::new(Account {
data: vec![0; space as usize],
..Account::default()
};
});
let mut accounts = vec![(&config_pubkey, true, &mut config_account)];
let mut keyed_accounts = create_keyed_is_signer_accounts(&mut accounts);
assert_eq!(
@ -172,7 +175,7 @@ mod tests {
let (_, config_account) = create_config_account(keys.clone());
assert_eq!(
Some(MyConfig::default()),
deserialize(get_config_data(&config_account.data).unwrap()).ok()
deserialize(get_config_data(&config_account.borrow().data).unwrap()).ok()
);
}
@ -193,7 +196,7 @@ mod tests {
);
assert_eq!(
Some(my_config),
deserialize(get_config_data(&config_account.data).unwrap()).ok()
deserialize(get_config_data(&config_account.borrow().data).unwrap()).ok()
);
}
@ -250,8 +253,8 @@ mod tests {
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let mut signer0_account = Account::default();
let mut signer1_account = Account::default();
let mut signer0_account = RefCell::new(Account::default());
let mut signer1_account = RefCell::new(Account::default());
let mut accounts = vec![
(&config_pubkey, true, &mut config_account),
(&signer0_pubkey, true, &mut signer0_account),
@ -262,11 +265,11 @@ mod tests {
process_instruction(&id(), &mut keyed_accounts, &instruction.data),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.data).unwrap();
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
assert_eq!(meta_data.keys, keys);
assert_eq!(
Some(my_config),
deserialize(get_config_data(&config_account.data).unwrap()).ok()
deserialize(get_config_data(&config_account.borrow().data).unwrap()).ok()
);
}
@ -282,7 +285,7 @@ mod tests {
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &my_config);
let mut signer0_account = Account::default();
let mut signer0_account = RefCell::new(Account::default());
let mut accounts = vec![(&signer0_pubkey, true, &mut signer0_account)];
let mut keyed_accounts = create_keyed_is_signer_accounts(&mut accounts);
assert_eq!(
@ -296,8 +299,8 @@ mod tests {
solana_logger::setup();
let signer0_pubkey = Pubkey::new_rand();
let signer1_pubkey = Pubkey::new_rand();
let mut signer0_account = Account::default();
let mut signer1_account = Account::default();
let mut signer0_account = RefCell::new(Account::default());
let mut signer1_account = RefCell::new(Account::default());
let keys = vec![(signer0_pubkey, true)];
let (config_keypair, mut config_account) = create_config_account(keys.clone());
let config_pubkey = config_keypair.pubkey();
@ -335,9 +338,9 @@ mod tests {
let signer0_pubkey = Pubkey::new_rand();
let signer1_pubkey = Pubkey::new_rand();
let signer2_pubkey = Pubkey::new_rand();
let mut signer0_account = Account::default();
let mut signer1_account = Account::default();
let mut signer2_account = Account::default();
let mut signer0_account = RefCell::new(Account::default());
let mut signer1_account = RefCell::new(Account::default());
let mut signer2_account = RefCell::new(Account::default());
let keys = vec![
(pubkey, false),
(signer0_pubkey, true),
@ -373,11 +376,11 @@ mod tests {
process_instruction(&id(), &mut keyed_accounts, &instruction.data),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.data).unwrap();
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
assert_eq!(meta_data.keys, keys);
assert_eq!(
new_config,
MyConfig::deserialize(get_config_data(&config_account.data).unwrap()).unwrap()
MyConfig::deserialize(get_config_data(&config_account.borrow().data).unwrap()).unwrap()
);
// Attempt update with incomplete signatures
@ -420,7 +423,7 @@ mod tests {
solana_logger::setup();
let pubkey = Pubkey::new_rand();
let signer0_pubkey = Pubkey::new_rand();
let mut signer0_account = Account::default();
let mut signer0_account = RefCell::new(Account::default());
let keys = vec![
(pubkey, false),
(signer0_pubkey, true),
@ -460,11 +463,11 @@ mod tests {
process_instruction(&id(), &mut keyed_accounts, &instruction.data),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.data).unwrap();
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
assert_eq!(meta_data.keys, keys);
assert_eq!(
new_config,
MyConfig::deserialize(get_config_data(&config_account.data).unwrap()).unwrap()
MyConfig::deserialize(get_config_data(&config_account.borrow().data).unwrap()).unwrap()
);
// Attempt update with incomplete signatures

View File

@ -164,15 +164,16 @@ impl ExchangeProcessor {
error!("Not enough accounts");
return Err(InstructionError::InvalidArgument);
}
Self::is_account_unallocated(&keyed_accounts[NEW_ACCOUNT_INDEX].account.data)?;
Self::is_account_unallocated(&keyed_accounts[NEW_ACCOUNT_INDEX].try_account_ref()?.data)?;
Self::serialize(
&ExchangeState::Account(
TokenAccountInfo::default()
.owner(&keyed_accounts[OWNER_INDEX].unsigned_key())
.tokens(100_000, 100_000, 100_000, 100_000),
),
&mut keyed_accounts[NEW_ACCOUNT_INDEX].account.data,
&mut keyed_accounts[NEW_ACCOUNT_INDEX]
.try_account_ref_mut()?
.data,
)
}
@ -191,13 +192,13 @@ impl ExchangeProcessor {
}
let mut to_account =
Self::deserialize_account(&keyed_accounts[TO_ACCOUNT_INDEX].account.data)?;
Self::deserialize_account(&keyed_accounts[TO_ACCOUNT_INDEX].try_account_ref()?.data)?;
if &faucet::id() == keyed_accounts[FROM_ACCOUNT_INDEX].unsigned_key() {
to_account.tokens[token] += tokens;
} else {
let state: ExchangeState =
bincode::deserialize(&keyed_accounts[FROM_ACCOUNT_INDEX].account.data)
bincode::deserialize(&keyed_accounts[FROM_ACCOUNT_INDEX].try_account_ref()?.data)
.map_err(Self::map_to_invalid_arg)?;
match state {
ExchangeState::Account(mut from_account) => {
@ -216,7 +217,9 @@ impl ExchangeProcessor {
Self::serialize(
&ExchangeState::Account(from_account),
&mut keyed_accounts[FROM_ACCOUNT_INDEX].account.data,
&mut keyed_accounts[FROM_ACCOUNT_INDEX]
.try_account_ref_mut()?
.data,
)?;
}
ExchangeState::Trade(mut from_trade) => {
@ -244,7 +247,9 @@ impl ExchangeProcessor {
Self::serialize(
&ExchangeState::Trade(from_trade),
&mut keyed_accounts[FROM_ACCOUNT_INDEX].account.data,
&mut keyed_accounts[FROM_ACCOUNT_INDEX]
.try_account_ref_mut()?
.data,
)?;
}
_ => {
@ -256,7 +261,7 @@ impl ExchangeProcessor {
Self::serialize(
&ExchangeState::Account(to_account),
&mut keyed_accounts[TO_ACCOUNT_INDEX].account.data,
&mut keyed_accounts[TO_ACCOUNT_INDEX].try_account_ref_mut()?.data,
)
}
@ -273,9 +278,10 @@ impl ExchangeProcessor {
return Err(InstructionError::InvalidArgument);
}
Self::is_account_unallocated(&keyed_accounts[ORDER_INDEX].account.data)?;
Self::is_account_unallocated(&keyed_accounts[ORDER_INDEX].try_account_ref()?.data)?;
let mut account = Self::deserialize_account(&keyed_accounts[ACCOUNT_INDEX].account.data)?;
let mut account =
Self::deserialize_account(&keyed_accounts[ACCOUNT_INDEX].try_account_ref_mut()?.data)?;
if &account.owner != keyed_accounts[OWNER_INDEX].unsigned_key() {
error!("Signer does not own account");
@ -308,11 +314,11 @@ impl ExchangeProcessor {
price: info.price,
tokens_settled: 0,
}),
&mut keyed_accounts[ORDER_INDEX].account.data,
&mut keyed_accounts[ORDER_INDEX].try_account_ref_mut()?.data,
)?;
Self::serialize(
&ExchangeState::Account(account),
&mut keyed_accounts[ACCOUNT_INDEX].account.data,
&mut keyed_accounts[ACCOUNT_INDEX].try_account_ref_mut()?.data,
)
}
@ -325,7 +331,7 @@ impl ExchangeProcessor {
return Err(InstructionError::InvalidArgument);
}
let order = Self::deserialize_order(&keyed_accounts[ORDER_INDEX].account.data)?;
let order = Self::deserialize_order(&keyed_accounts[ORDER_INDEX].try_account_ref()?.data)?;
if &order.owner != keyed_accounts[OWNER_INDEX].unsigned_key() {
error!("Signer does not own trade");
@ -344,7 +350,7 @@ impl ExchangeProcessor {
// Turn trade order into a token account
Self::serialize(
&ExchangeState::Account(account),
&mut keyed_accounts[ORDER_INDEX].account.data,
&mut keyed_accounts[ORDER_INDEX].try_account_ref_mut()?.data,
)
}
@ -358,11 +364,13 @@ impl ExchangeProcessor {
return Err(InstructionError::InvalidArgument);
}
let mut to_order = Self::deserialize_order(&keyed_accounts[TO_ORDER_INDEX].account.data)?;
let mut to_order =
Self::deserialize_order(&keyed_accounts[TO_ORDER_INDEX].try_account_ref()?.data)?;
let mut from_order =
Self::deserialize_order(&keyed_accounts[FROM_ORDER_INDEX].account.data)?;
let mut profit_account =
Self::deserialize_account(&keyed_accounts[PROFIT_ACCOUNT_INDEX].account.data)?;
Self::deserialize_order(&keyed_accounts[FROM_ORDER_INDEX].try_account_ref()?.data)?;
let mut profit_account = Self::deserialize_account(
&keyed_accounts[PROFIT_ACCOUNT_INDEX].try_account_ref()?.data,
)?;
if to_order.side != OrderSide::Ask {
error!("To trade is not a To");
@ -397,12 +405,12 @@ impl ExchangeProcessor {
// Turn into token account
Self::serialize(
&ExchangeState::Account(Self::trade_to_token_account(&from_order)),
&mut keyed_accounts[TO_ORDER_INDEX].account.data,
&mut keyed_accounts[TO_ORDER_INDEX].try_account_ref_mut()?.data,
)?;
} else {
Self::serialize(
&ExchangeState::Trade(to_order),
&mut keyed_accounts[TO_ORDER_INDEX].account.data,
&mut keyed_accounts[TO_ORDER_INDEX].try_account_ref_mut()?.data,
)?;
}
@ -410,18 +418,20 @@ impl ExchangeProcessor {
// Turn into token account
Self::serialize(
&ExchangeState::Account(Self::trade_to_token_account(&from_order)),
&mut keyed_accounts[FROM_ORDER_INDEX].account.data,
&mut keyed_accounts[FROM_ORDER_INDEX].try_account_ref_mut()?.data,
)?;
} else {
Self::serialize(
&ExchangeState::Trade(from_order),
&mut keyed_accounts[FROM_ORDER_INDEX].account.data,
&mut keyed_accounts[FROM_ORDER_INDEX].try_account_ref_mut()?.data,
)?;
}
Self::serialize(
&ExchangeState::Account(profit_account),
&mut keyed_accounts[PROFIT_ACCOUNT_INDEX].account.data,
&mut keyed_accounts[PROFIT_ACCOUNT_INDEX]
.try_account_ref_mut()?
.data,
)
}
}

View File

@ -11,6 +11,7 @@ use solana_sdk::{
move_loader::id,
pubkey::Pubkey,
sysvar::rent,
account_utils::State,
};
use types::{
account_address::AccountAddress,
@ -177,7 +178,7 @@ impl MoveProcessor {
let mut keyed_accounts_iter = keyed_accounts.iter();
let genesis = next_keyed_account(&mut keyed_accounts_iter)?;
match limited_deserialize(&genesis.account.data)? {
match limited_deserialize(&genesis.try_account_ref()?.data)? {
LibraAccountState::Genesis(write_set) => data_store.apply_write_set(&write_set),
_ => {
debug!("Must include a genesis account");
@ -186,7 +187,7 @@ impl MoveProcessor {
}
for keyed_account in keyed_accounts_iter {
match limited_deserialize(&keyed_account.account.data)? {
match limited_deserialize(&keyed_account.try_account_ref()?.data)? {
LibraAccountState::User(owner, write_set) => {
if owner != *genesis.unsigned_key() {
debug!("User account must be owned by this genesis");
@ -230,7 +231,7 @@ impl MoveProcessor {
let write_set = write_set.freeze().unwrap();
Self::serialize_and_enforce_length(
&LibraAccountState::Genesis(write_set),
&mut genesis.account.data,
&mut genesis.try_account_ref_mut()?.data,
)?;
// Now do the rest of the accounts
@ -238,11 +239,11 @@ impl MoveProcessor {
let write_set = write_sets
.remove(&pubkey_to_address(keyed_account.unsigned_key()))
.ok_or_else(Self::missing_account)?;
if !keyed_account.account.executable {
if !keyed_account.executable()? {
// Only write back non-executable accounts
Self::serialize_and_enforce_length(
&LibraAccountState::User(genesis_key, write_set),
&mut keyed_account.account.data,
&mut keyed_account.try_account_ref_mut()?.data,
)?;
}
}
@ -268,15 +269,15 @@ impl MoveProcessor {
let offset = offset as usize;
let len = bytes.len();
trace!("Write: offset={} length={}", offset, len);
if keyed_account.account.data.len() < offset + len {
if keyed_account.data_len()? < offset + len {
debug!(
"Error: Write overflow: {} < {}",
keyed_account.account.data.len(),
keyed_account.data_len()?,
offset + len
);
return Err(InstructionError::AccountDataTooSmall);
}
keyed_account.account.data[offset..offset + len].copy_from_slice(&bytes);
keyed_account.try_account_ref_mut()?.data[offset..offset + len].copy_from_slice(&bytes);
Ok(())
}
@ -292,7 +293,7 @@ impl MoveProcessor {
rent::verify_rent_exemption(&finalized, &rent)?;
match limited_deserialize(&finalized.account.data)? {
match finalized.state()? {
LibraAccountState::CompiledScript(string) => {
let script: Script = serde_json::from_str(&string).map_err(map_json_error)?;
let compiled_script =
@ -314,7 +315,7 @@ impl MoveProcessor {
.map_err(map_failure_error)?;
Self::serialize_and_enforce_length(
&LibraAccountState::VerifiedScript { script_bytes },
&mut finalized.account.data,
&mut finalized.try_account_ref_mut()?.data,
)?;
info!("Finalize script: {:?}", finalized.unsigned_key());
}
@ -339,7 +340,7 @@ impl MoveProcessor {
.ok_or_else(Self::missing_account)?;
Self::serialize_and_enforce_length(
&LibraAccountState::PublishedModule(write_set),
&mut finalized.account.data,
&mut finalized.try_account_ref_mut()?.data,
)?;
if !write_sets.is_empty() {
@ -355,7 +356,7 @@ impl MoveProcessor {
}
};
finalized.account.executable = true;
finalized.try_account_ref_mut()?.executable = true;
Ok(())
}
@ -365,17 +366,17 @@ impl MoveProcessor {
amount: u64,
) -> Result<(), InstructionError> {
let mut keyed_accounts_iter = keyed_accounts.iter_mut();
let script = next_keyed_account(&mut keyed_accounts_iter)?;
let genesis = next_keyed_account(&mut keyed_accounts_iter)?;
if script.account.owner != id() {
debug!("Error: Move script account not owned by Move loader");
if genesis.owner()? != id() {
debug!("Error: Move genesis account not owned by Move loader");
return Err(InstructionError::InvalidArgument);
}
match limited_deserialize(&script.account.data)? {
match genesis.state()? {
LibraAccountState::Unallocated => Self::serialize_and_enforce_length(
&LibraAccountState::create_genesis(amount)?,
&mut script.account.data,
&mut genesis.try_account_ref_mut()?.data,
),
_ => {
debug!("Error: Must provide an unallocated account");
@ -399,11 +400,11 @@ impl MoveProcessor {
function_name
);
if script.account.owner != id() {
if script.owner()? != id() {
debug!("Error: Move script account not owned by Move loader");
return Err(InstructionError::InvalidArgument);
}
if !script.account.executable {
if !script.executable()? {
debug!("Error: Move script account not executable");
return Err(InstructionError::AccountNotExecutable);
}
@ -411,7 +412,7 @@ impl MoveProcessor {
let data_accounts = keyed_accounts_iter.into_slice();
let mut data_store = Self::keyed_accounts_to_data_store(&data_accounts)?;
let verified_script = Self::deserialize_verified_script(&script.account.data)?;
let verified_script = Self::deserialize_verified_script(&script.try_account_ref()?.data)?;
let output = Self::execute(
sender_address,
@ -435,7 +436,7 @@ impl MoveProcessor {
) -> Result<(), InstructionError> {
solana_logger::setup();
if is_executable(keyed_accounts) {
if is_executable(keyed_accounts)? {
match limited_deserialize(&instruction_data)? {
Executable::RunScript {
sender_address,
@ -463,6 +464,7 @@ mod tests {
use solana_sdk::account::Account;
use solana_sdk::rent::Rent;
use solana_sdk::sysvar::rent;
use std::cell::RefCell;
const BIG_ENOUGH: usize = 10_000;
@ -500,13 +502,13 @@ mod tests {
let sender_address = AccountAddress::default();
let mut script = LibraAccount::create_script(&sender_address, code, vec![]);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
];
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
let _ = MoveProcessor::deserialize_verified_script(&script.account.data).unwrap();
let _ = MoveProcessor::deserialize_verified_script(&script.account.borrow().data).unwrap();
}
#[test]
@ -525,10 +527,11 @@ mod tests {
assert_eq!(
bincode::deserialize::<LibraAccountState>(
&LibraAccount::create_genesis(amount).account.data
&LibraAccount::create_genesis(amount).account.borrow().data
)
.unwrap(),
bincode::deserialize::<LibraAccountState>(&keyed_accounts[0].account.data).unwrap()
bincode::deserialize::<LibraAccountState>(&keyed_accounts[0].account.borrow().data)
.unwrap()
);
}
@ -542,7 +545,7 @@ mod tests {
let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
@ -577,12 +580,16 @@ mod tests {
";
let mut module = LibraAccount::create_module(code, vec![]);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&module.key, true, &mut module.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
keyed_accounts[0]
.account
.borrow_mut()
.data
.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
}
@ -602,7 +609,7 @@ mod tests {
let mut genesis = LibraAccount::create_genesis(1_000_000_000);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
@ -639,7 +646,7 @@ mod tests {
let _script = next_libra_account(&mut accounts_iter).unwrap();
let genesis = next_libra_account(&mut accounts_iter).unwrap();
let payee = next_libra_account(&mut accounts_iter).unwrap();
match bincode::deserialize(&payee.account.data).unwrap() {
match bincode::deserialize(&payee.account.borrow().data).unwrap() {
LibraAccountState::User(owner, write_set) => {
if owner != genesis.key {
panic!();
@ -677,7 +684,7 @@ mod tests {
let mut payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
@ -735,12 +742,16 @@ mod tests {
let mut module = LibraAccount::create_module(&code, vec![]);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&module.key, true, &mut module.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
keyed_accounts[0]
.account
.borrow_mut()
.data
.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
@ -769,12 +780,15 @@ mod tests {
",
module.address
);
let mut script =
LibraAccount::create_script(&genesis.address, &code, vec![&module.account.data]);
let mut script = LibraAccount::create_script(
&genesis.address,
&code,
vec![&module.account.borrow().data],
);
let mut payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
@ -824,7 +838,7 @@ mod tests {
let mut payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let mut rent_account = rent::create_account(1, &Rent::free());
let mut rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let mut keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &mut script.account),
KeyedAccount::new(&rent_id, false, &mut rent_account),
@ -850,9 +864,9 @@ mod tests {
.unwrap();
Ok(vec![
LibraAccount::new(script.key, script.account),
LibraAccount::new(genesis.key, genesis.account),
LibraAccount::new(payee.key, payee.account),
LibraAccount::new(script.key, script.account.into_inner()),
LibraAccount::new(genesis.key, genesis.account.into_inner()),
LibraAccount::new(payee.key, payee.account.into_inner()),
])
}
@ -860,7 +874,7 @@ mod tests {
struct LibraAccount {
pub key: Pubkey,
pub address: AccountAddress,
pub account: Account,
pub account: RefCell<Account>,
}
pub fn next_libra_account<I: Iterator>(iter: &mut I) -> Result<I::Item, InstructionError> {
@ -873,7 +887,7 @@ mod tests {
Self {
key,
address,
account,
account: RefCell::new(account),
}
}
@ -898,10 +912,10 @@ mod tests {
owner: id(),
..Account::default()
};
let mut genesis = Self::new(Pubkey::new_rand(), account);
let genesis = Self::new(Pubkey::new_rand(), account);
let pre_data = LibraAccountState::create_genesis(amount).unwrap();
let _hi = "hello";
genesis.account.data = bincode::serialize(&pre_data).unwrap();
genesis.account.borrow_mut().data = bincode::serialize(&pre_data).unwrap();
genesis
}
@ -910,24 +924,20 @@ mod tests {
code: &str,
deps: Vec<&Vec<u8>>,
) -> Self {
let mut script = Self::create_unallocated(0);
script.account.data = bincode::serialize(&LibraAccountState::create_script(
sender_address,
code,
deps,
))
let script = Self::create_unallocated(0);
script.account.borrow_mut().data = bincode::serialize(
&LibraAccountState::create_script(sender_address, code, deps),
)
.unwrap();
script
}
pub fn create_module(code: &str, deps: Vec<&Vec<u8>>) -> Self {
let mut module = Self::create_unallocated(0);
module.account.data = bincode::serialize(&LibraAccountState::create_module(
&module.address,
code,
deps,
))
let module = Self::create_unallocated(0);
module.account.borrow_mut().data = bincode::serialize(
&LibraAccountState::create_module(&module.address, code, deps),
)
.unwrap();
module

View File

@ -35,7 +35,7 @@ pub fn process_instruction(
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
let account_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
let mut account_owner_pubkey: Pubkey =
limited_deserialize(&account_keyed_account.account.data)?;
limited_deserialize(&account_keyed_account.try_account_ref()?.data)?;
if account_owner_pubkey == Pubkey::default() {
account_owner_pubkey = new_owner_pubkey;
@ -48,11 +48,9 @@ pub fn process_instruction(
)?;
}
serialize_into(
&mut account_keyed_account.account.data[..],
&account_owner_pubkey,
)
.map_err(|_| InstructionError::AccountDataTooSmall)
let mut account = account_keyed_account.try_account_ref_mut()?;
serialize_into(&mut account.data[..], &account_owner_pubkey)
.map_err(|_| InstructionError::AccountDataTooSmall)
}
#[cfg(test)]
@ -156,7 +154,7 @@ mod tests {
let mut account_owner_pubkey = Pubkey::new_rand();
let owner_pubkey = account_owner_pubkey;
let new_owner_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &system_program::id());
let mut account = Account::new_ref(1, 0, &system_program::id());
let owner_keyed_account = KeyedAccount::new(&owner_pubkey, false, &mut account); // <-- Attack! Setting owner without the original owner's signature.
let err = set_owner(
&mut account_owner_pubkey,
@ -171,7 +169,7 @@ mod tests {
fn test_ownable_incorrect_owner() {
let mut account_owner_pubkey = Pubkey::new_rand();
let new_owner_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &system_program::id());
let mut account = Account::new_ref(1, 0, &system_program::id());
let mallory_pubkey = Pubkey::new_rand(); // <-- Attack! Signing with wrong pubkey
let owner_keyed_account = KeyedAccount::new(&mallory_pubkey, true, &mut account);
let err = set_owner(

View File

@ -67,18 +67,19 @@ pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionE
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
Config::from(account.account).ok_or(InstructionError::InvalidArgument)
Config::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::pubkey::Pubkey;
use std::cell::RefCell;
#[test]
fn test() {
let mut account = create_account(0, &Config::default());
assert_eq!(Config::from(&account), Some(Config::default()));
let mut account = RefCell::new(create_account(0, &Config::default()));
assert_eq!(Config::from(&account.borrow()), Some(Config::default()));
assert_eq!(
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &mut account)),
Err(InstructionError::InvalidArgument)

View File

@ -448,13 +448,18 @@ mod tests {
use super::*;
use bincode::serialize;
use solana_sdk::{account::Account, rent::Rent, sysvar::stake_history::StakeHistory};
use std::cell::RefCell;
fn create_default_account() -> RefCell<Account> {
RefCell::new(Account::default())
}
fn process_instruction(instruction: &Instruction) -> Result<(), InstructionError> {
let mut accounts: Vec<_> = instruction
.accounts
.iter()
.map(|meta| {
if sysvar::clock::check_id(&meta.pubkey) {
RefCell::new(if sysvar::clock::check_id(&meta.pubkey) {
sysvar::clock::Clock::default().create_account(1)
} else if sysvar::rewards::check_id(&meta.pubkey) {
sysvar::rewards::create_account(1, 0.0, 0.0)
@ -466,7 +471,7 @@ mod tests {
sysvar::rent::create_account(1, &Rent::default())
} else {
Account::default()
}
})
})
.collect();
@ -576,7 +581,7 @@ mod tests {
&mut [KeyedAccount::new(
&Pubkey::default(),
false,
&mut Account::default(),
&mut create_default_account(),
)],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
@ -592,8 +597,8 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default(),),
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),)
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account(),),
KeyedAccount::new(&sysvar::rent::id(), false, &mut create_default_account(),)
],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
@ -609,11 +614,11 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default(),),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(
&sysvar::rent::id(),
false,
&mut sysvar::rent::create_account(0, &Rent::default())
&mut RefCell::new(sysvar::rent::create_account(0, &Rent::default()))
)
],
&serialize(&StakeInstruction::Initialize(
@ -632,8 +637,8 @@ mod tests {
&mut [KeyedAccount::new(
&Pubkey::default(),
false,
&mut Account::default(),
)],
&mut create_default_account()
),],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -646,8 +651,8 @@ mod tests {
&mut [KeyedAccount::new(
&Pubkey::default(),
false,
&mut Account::default()
),],
&mut create_default_account()
)],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -658,8 +663,8 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
],
&serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
),
@ -671,11 +676,11 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
],
&serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
),
@ -687,17 +692,17 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), true, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(
&sysvar::clock::id(),
false,
&mut sysvar::clock::Clock::default().create_account(1)
&mut RefCell::new(sysvar::clock::Clock::default().create_account(1))
),
KeyedAccount::new(
&config::id(),
false,
&mut config::create_account(0, &config::Config::default())
&mut RefCell::new(config::create_account(0, &config::Config::default()))
),
],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
@ -710,18 +715,21 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(
&sysvar::rewards::id(),
false,
&mut sysvar::rewards::create_account(1, 0.0, 0.0)
&mut RefCell::new(sysvar::rewards::create_account(1, 0.0, 0.0))
),
KeyedAccount::new(
&sysvar::stake_history::id(),
false,
&mut sysvar::stake_history::create_account(1, &StakeHistory::default())
&mut RefCell::new(sysvar::stake_history::create_account(
1,
&StakeHistory::default()
))
),
],
&serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
@ -734,17 +742,20 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(
&sysvar::rewards::id(),
false,
&mut sysvar::rewards::create_account(1, 0.0, 0.0)
&mut RefCell::new(sysvar::rewards::create_account(1, 0.0, 0.0))
),
KeyedAccount::new(
&sysvar::stake_history::id(),
false,
&mut sysvar::stake_history::create_account(1, &StakeHistory::default())
&mut RefCell::new(sysvar::stake_history::create_account(
1,
&StakeHistory::default()
))
),
],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
@ -759,7 +770,7 @@ mod tests {
&mut [KeyedAccount::new(
&Pubkey::default(),
false,
&mut Account::default()
&mut create_default_account()
)],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
),
@ -771,11 +782,11 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut create_default_account()),
KeyedAccount::new(
&sysvar::rewards::id(),
false,
&mut sysvar::rewards::create_account(1, 0.0, 0.0)
&mut RefCell::new(sysvar::rewards::create_account(1, 0.0, 0.0))
),
],
&serialize(&StakeInstruction::Deactivate).unwrap(),

View File

@ -553,9 +553,9 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
rent: &Rent,
) -> Result<(), InstructionError> {
if let StakeState::Uninitialized = self.state()? {
let rent_exempt_reserve = rent.minimum_balance(self.account.data.len());
let rent_exempt_reserve = rent.minimum_balance(self.data_len()?);
if rent_exempt_reserve < self.account.lamports {
if rent_exempt_reserve < self.lamports()? {
self.set_state(&StakeState::Initialized(Meta {
rent_exempt_reserve,
authorized: *authorized,
@ -602,9 +602,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
StakeState::Initialized(meta) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
let stake = Stake::new(
self.account
.lamports
.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;)
self.lamports()?.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;)
vote_account.unsigned_key(),
&vote_account.state()?,
clock.epoch,
@ -659,13 +657,13 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
Some(stake_history),
)
{
if rewards_account.account.lamports < (stakers_reward + voters_reward) {
if rewards_account.lamports()? < (stakers_reward + voters_reward) {
return Err(InstructionError::UnbalancedInstruction);
}
rewards_account.account.lamports -= stakers_reward + voters_reward;
rewards_account.try_account_ref_mut()?.lamports -= stakers_reward + voters_reward;
self.account.lamports += stakers_reward;
vote_account.account.lamports += voters_reward;
self.try_account_ref_mut()?.lamports += stakers_reward;
vote_account.try_account_ref_mut()?.lamports += voters_reward;
stake.credits_observed = credits_observed;
stake.delegation.stake += stakers_reward;
@ -688,7 +686,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
) -> Result<(), InstructionError> {
if let StakeState::Uninitialized = split.state()? {
// verify enough account lamports
if lamports > self.account.lamports {
if lamports > self.lamports()? {
return Err(InstructionError::InsufficientFunds);
}
@ -697,9 +695,9 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
// verify enough lamports for rent in new stake with the split
if split.account.lamports + lamports < meta.rent_exempt_reserve
if split.lamports()? + lamports < meta.rent_exempt_reserve
// verify enough lamports left in previous stake and not full withdrawal
|| (lamports + meta.rent_exempt_reserve > self.account.lamports && lamports != self.account.lamports)
|| (lamports + meta.rent_exempt_reserve > self.lamports()? && lamports != self.lamports()?)
{
return Err(InstructionError::InsufficientFunds);
}
@ -709,10 +707,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
// this could represent a small loss of staked lamports
// if the split account starts out with a zero balance
let split_stake = stake.split(
lamports
- meta
.rent_exempt_reserve
.saturating_sub(split.account.lamports),
lamports - meta.rent_exempt_reserve.saturating_sub(split.lamports()?),
)?;
self.set_state(&StakeState::Stake(meta, stake))?;
@ -724,7 +719,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
// enough lamports for rent in new stake
if lamports < meta.rent_exempt_reserve
// verify enough lamports left in previous stake
|| (lamports + meta.rent_exempt_reserve > self.account.lamports && lamports != self.account.lamports)
|| (lamports + meta.rent_exempt_reserve > self.lamports()? && lamports != self.lamports()?)
{
return Err(InstructionError::InsufficientFunds);
}
@ -739,8 +734,8 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
_ => return Err(InstructionError::InvalidAccountData),
}
split.account.lamports += lamports;
self.account.lamports -= lamports;
split.try_account_ref_mut()?.lamports += lamports;
self.try_account_ref_mut()?.lamports -= lamports;
Ok(())
} else {
Err(InstructionError::InvalidAccountData)
@ -792,20 +787,20 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
// if the stake is active, we mustn't allow the account to go away
if is_staked // line coverage for branch coverage
&& lamports + reserve > self.account.lamports
&& lamports + reserve > self.lamports()?
{
return Err(InstructionError::InsufficientFunds);
}
if lamports != self.account.lamports // not a full withdrawal
&& lamports + reserve > self.account.lamports
if lamports != self.lamports()? // not a full withdrawal
&& lamports + reserve > self.lamports()?
{
assert!(!is_staked);
return Err(InstructionError::InsufficientFunds);
}
self.account.lamports -= lamports;
to.account.lamports += lamports;
self.try_account_ref_mut()?.lamports -= lamports;
to.try_account_ref_mut()?.lamports += lamports;
Ok(())
}
}
@ -903,6 +898,7 @@ mod tests {
use crate::id;
use solana_sdk::{account::Account, pubkey::Pubkey, system_program};
use solana_vote_program::vote_state;
use std::cell::RefCell;
impl Meta {
pub fn auto(authorized: &Pubkey) -> Self {
@ -1004,14 +1000,18 @@ mod tests {
vote_state.process_slot_vote_unchecked(i);
}
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&vote_state).unwrap();
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Initialized(Meta {
authorized: Authorized {
@ -1061,7 +1061,7 @@ mod tests {
.is_ok());
// verify that delegate_stake() looks right, compare against hand-rolled
let stake = StakeState::stake_from(&stake_keyed_account.account).unwrap();
let stake = StakeState::stake_from(&stake_keyed_account.account.borrow()).unwrap();
assert_eq!(
stake,
Stake {
@ -1462,7 +1462,7 @@ mod tests {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account =
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
Account::new_ref(stake_lamports, std::mem::size_of::<StakeState>(), &id());
// unsigned keyed account
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
@ -1496,7 +1496,7 @@ mod tests {
);
// check that we see what we expect
assert_eq!(
StakeState::from(&stake_keyed_account.account).unwrap(),
StakeState::from(&stake_keyed_account.account.borrow()).unwrap(),
StakeState::Initialized(Meta {
lockup: Lockup {
unix_timestamp: 0,
@ -1525,7 +1525,7 @@ mod tests {
fn test_deactivate_stake() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -1548,8 +1548,12 @@ mod tests {
// Staking
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
assert_eq!(
@ -1587,7 +1591,7 @@ mod tests {
fn test_withdraw_stake() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -1598,7 +1602,7 @@ mod tests {
let mut clock = sysvar::clock::Clock::default();
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_account = Account::new_ref(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
// no signers, should fail
@ -1628,10 +1632,10 @@ mod tests {
),
Ok(())
);
assert_eq!(stake_account.lamports, 0);
assert_eq!(stake_account.borrow().lamports, 0);
// reset balance
stake_account.lamports = stake_lamports;
stake_account.borrow_mut().lamports = stake_lamports;
// lockup
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
@ -1664,8 +1668,12 @@ mod tests {
// Stake some lamports (available lamports for withdrawals will reduce to zero)
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
assert_eq!(
@ -1679,7 +1687,7 @@ mod tests {
);
// simulate rewards
stake_account.lamports += 10;
stake_account.borrow_mut().lamports += 10;
// withdrawal before deactivate works for rewards amount
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
@ -1695,7 +1703,7 @@ mod tests {
);
// simulate rewards
stake_account.lamports += 10;
stake_account.borrow_mut().lamports += 10;
// withdrawal of rewards fails if not in excess of stake
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
@ -1743,7 +1751,7 @@ mod tests {
),
Ok(())
);
assert_eq!(stake_account.lamports, 0);
assert_eq!(stake_account.borrow().lamports, 0);
}
#[test]
@ -1751,7 +1759,7 @@ mod tests {
let stake_pubkey = Pubkey::new_rand();
let total_lamports = 100;
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
total_lamports,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -1764,15 +1772,19 @@ mod tests {
future.epoch += 16;
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_account = Account::new_ref(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
// Stake some lamports (available lamports for withdrawals will reduce)
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
let signers = vec![stake_pubkey].into_iter().collect();
@ -1789,9 +1801,11 @@ mod tests {
let stake_history = create_stake_history_from_delegations(
None,
0..future.epoch,
&[StakeState::stake_from(&stake_keyed_account.account)
.unwrap()
.delegation],
&[
StakeState::stake_from(&stake_keyed_account.account.borrow())
.unwrap()
.delegation,
],
);
// Try to withdraw stake
@ -1811,7 +1825,7 @@ mod tests {
fn test_withdraw_stake_invalid_state() {
let stake_pubkey = Pubkey::new_rand();
let total_lamports = 100;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
total_lamports,
&StakeState::RewardsPool,
std::mem::size_of::<StakeState>(),
@ -1820,7 +1834,7 @@ mod tests {
.expect("stake_account");
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_account = Account::new_ref(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let signers = vec![stake_pubkey].into_iter().collect();
@ -1841,7 +1855,7 @@ mod tests {
let stake_pubkey = Pubkey::new_rand();
let custodian = Pubkey::new_rand();
let total_lamports = 100;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
total_lamports,
&StakeState::Initialized(Meta {
lockup: Lockup {
@ -1857,7 +1871,7 @@ mod tests {
.expect("stake_account");
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_account = Account::new_ref(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
@ -1893,7 +1907,7 @@ mod tests {
);
}
// reset balance
stake_keyed_account.account.lamports = total_lamports;
stake_keyed_account.account.borrow_mut().lamports = total_lamports;
// lockup has expired
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
@ -1999,7 +2013,7 @@ mod tests {
rewards.validator_point_value = 100.0;
let rewards_pool_pubkey = Pubkey::new_rand();
let mut rewards_pool_account = Account::new_data(
let mut rewards_pool_account = Account::new_ref_data(
std::u64::MAX,
&StakeState::RewardsPool,
&crate::rewards_pools::id(),
@ -2010,7 +2024,7 @@ mod tests {
let stake_pubkey = Pubkey::default();
let stake_lamports = 100;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -2021,8 +2035,12 @@ mod tests {
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
// not delegated yet, deserialization fails
@ -2044,9 +2062,11 @@ mod tests {
let stake_history = create_stake_history_from_delegations(
Some(100),
0..10,
&[StakeState::stake_from(&stake_keyed_account.account)
.unwrap()
.delegation],
&[
StakeState::stake_from(&stake_keyed_account.account.borrow())
.unwrap()
.delegation,
],
);
// no credits to claim
@ -2071,10 +2091,14 @@ mod tests {
Err(InstructionError::InvalidAccountData)
);
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut vote_state = VoteState::from(&vote_account).unwrap();
let mut vote_state = VoteState::from(&vote_account.borrow()).unwrap();
// split credits 3:1 between staker and voter
vote_state.commission = 25;
// put in some credits in epoch 0 for which we should have a non-zero stake
@ -2083,11 +2107,11 @@ mod tests {
}
vote_state.increment_credits(2);
vote_state.to(&mut vote_account).unwrap();
vote_state.to(&mut vote_account.borrow_mut()).unwrap();
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
// some credits to claim, but rewards pool empty (shouldn't ever happen)
rewards_pool_keyed_account.account.lamports = 1;
rewards_pool_keyed_account.account.borrow_mut().lamports = 1;
assert_eq!(
stake_keyed_account.redeem_vote_credits(
&mut vote_keyed_account,
@ -2097,11 +2121,11 @@ mod tests {
),
Err(InstructionError::UnbalancedInstruction)
);
rewards_pool_keyed_account.account.lamports = std::u64::MAX;
rewards_pool_keyed_account.account.borrow_mut().lamports = std::u64::MAX;
// finally! some credits to claim
let stake_account_balance = stake_keyed_account.account.lamports;
let vote_account_balance = vote_keyed_account.account.lamports;
let stake_account_balance = stake_keyed_account.account.borrow().lamports;
let vote_account_balance = vote_keyed_account.account.borrow().lamports;
assert_eq!(
stake_keyed_account.redeem_vote_credits(
&mut vote_keyed_account,
@ -2111,8 +2135,8 @@ mod tests {
),
Ok(())
);
let staker_rewards = stake_keyed_account.account.lamports - stake_account_balance;
let voter_commission = vote_keyed_account.account.lamports - vote_account_balance;
let staker_rewards = stake_keyed_account.account.borrow().lamports - stake_account_balance;
let voter_commission = vote_keyed_account.account.borrow().lamports - vote_account_balance;
assert!(voter_commission > 0);
assert!(staker_rewards > 0);
assert!(
@ -2120,8 +2144,11 @@ mod tests {
"rewards should be split ~3:1"
);
// verify rewards are added to stake
let stake = StakeState::stake_from(&stake_keyed_account.account).unwrap();
assert_eq!(stake.delegation.stake, stake_keyed_account.account.lamports);
let stake = StakeState::stake_from(&stake_keyed_account.account.borrow()).unwrap();
assert_eq!(
stake.delegation.stake,
stake_keyed_account.account.borrow().lamports
);
let wrong_vote_pubkey = Pubkey::new_rand();
let mut wrong_vote_keyed_account =
@ -2143,7 +2170,7 @@ mod tests {
fn test_authorize_uninit() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::default(),
std::mem::size_of::<StakeState>(),
@ -2168,7 +2195,7 @@ mod tests {
fn test_authorize_lockup() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -2177,7 +2204,7 @@ mod tests {
.expect("stake_account");
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_account = Account::new_ref(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let clock = sysvar::clock::Clock::default();
@ -2204,7 +2231,7 @@ mod tests {
Ok(())
);
if let StakeState::Initialized(Meta { authorized, .. }) =
StakeState::from(&stake_keyed_account.account).unwrap()
StakeState::from(&stake_keyed_account.account.borrow()).unwrap()
{
assert_eq!(authorized.staker, stake_pubkey0);
assert_eq!(authorized.withdrawer, stake_pubkey0);
@ -2238,7 +2265,7 @@ mod tests {
Ok(())
);
if let StakeState::Initialized(Meta { authorized, .. }) =
StakeState::from(&stake_keyed_account.account).unwrap()
StakeState::from(&stake_keyed_account.account.borrow()).unwrap()
{
assert_eq!(authorized.staker, stake_pubkey2);
}
@ -2253,7 +2280,7 @@ mod tests {
Ok(())
);
if let StakeState::Initialized(Meta { authorized, .. }) =
StakeState::from(&stake_keyed_account.account).unwrap()
StakeState::from(&stake_keyed_account.account.borrow()).unwrap()
{
assert_eq!(authorized.staker, stake_pubkey2);
}
@ -2290,7 +2317,7 @@ mod tests {
fn test_split_source_uninitialized() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2299,7 +2326,7 @@ mod tests {
.expect("stake_account");
let split_stake_pubkey = Pubkey::new_rand();
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2328,8 +2355,8 @@ mod tests {
Ok(())
);
assert_eq!(
stake_keyed_account.account.lamports,
split_stake_keyed_account.account.lamports
stake_keyed_account.account.borrow().lamports,
split_stake_keyed_account.account.borrow().lamports
);
}
@ -2337,7 +2364,7 @@ mod tests {
fn test_split_split_not_uninitialized() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Stake(Meta::auto(&stake_pubkey), Stake::just_stake(stake_lamports)),
std::mem::size_of::<StakeState>(),
@ -2346,7 +2373,7 @@ mod tests {
.expect("stake_account");
let split_stake_pubkey = Pubkey::new_rand();
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -2379,7 +2406,7 @@ mod tests {
fn test_split_more_than_staked() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Stake(
Meta::auto(&stake_pubkey),
@ -2391,7 +2418,7 @@ mod tests {
.expect("stake_account");
let split_stake_pubkey = Pubkey::new_rand();
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2431,7 +2458,7 @@ mod tests {
Stake::just_stake(stake_lamports - rent_exempt_reserve),
),
] {
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
state,
std::mem::size_of::<StakeState>(),
@ -2442,7 +2469,7 @@ mod tests {
let mut stake_keyed_account =
KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2474,7 +2501,7 @@ mod tests {
);
// split account already has way enough lamports
split_stake_keyed_account.account.lamports = 1_000;
split_stake_keyed_account.account.borrow_mut().lamports = 1_000;
assert_eq!(
stake_keyed_account.split(
stake_lamports - rent_exempt_reserve,
@ -2499,9 +2526,12 @@ mod tests {
}
))
);
assert_eq!(stake_keyed_account.account.lamports, rent_exempt_reserve);
assert_eq!(
split_stake_keyed_account.account.lamports,
stake_keyed_account.account.borrow().lamports,
rent_exempt_reserve
);
assert_eq!(
split_stake_keyed_account.account.borrow().lamports,
1_000 + stake_lamports - rent_exempt_reserve
);
}
@ -2521,7 +2551,7 @@ mod tests {
StakeState::Initialized(Meta::auto(&stake_pubkey)),
StakeState::Stake(Meta::auto(&stake_pubkey), Stake::just_stake(stake_lamports)),
] {
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2532,7 +2562,7 @@ mod tests {
let mut split_stake_keyed_account =
KeyedAccount::new(&split_stake_pubkey, true, &mut split_stake_account);
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
state,
std::mem::size_of::<StakeState>(),
@ -2563,7 +2593,8 @@ mod tests {
);
// no lamport leakage
assert_eq!(
stake_keyed_account.account.lamports + split_stake_keyed_account.account.lamports,
stake_keyed_account.account.borrow().lamports
+ split_stake_keyed_account.account.borrow().lamports,
stake_lamports
);
@ -2604,7 +2635,7 @@ mod tests {
}
// reset
stake_keyed_account.account.lamports = stake_lamports;
stake_keyed_account.account.borrow_mut().lamports = stake_lamports;
}
}
@ -2631,7 +2662,7 @@ mod tests {
Stake::just_stake(stake_lamports - rent_exempt_reserve),
),
] {
let mut split_stake_account = Account::new_data_with_space(
let mut split_stake_account = Account::new_ref_data_with_space(
0,
&StakeState::Uninitialized,
std::mem::size_of::<StakeState>(),
@ -2642,7 +2673,7 @@ mod tests {
let mut split_stake_keyed_account =
KeyedAccount::new(&split_stake_pubkey, true, &mut split_stake_account);
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
state,
std::mem::size_of::<StakeState>(),
@ -2660,7 +2691,8 @@ mod tests {
// no lamport leakage
assert_eq!(
stake_keyed_account.account.lamports + split_stake_keyed_account.account.lamports,
stake_keyed_account.account.borrow().lamports
+ split_stake_keyed_account.account.borrow().lamports,
stake_lamports
);
@ -2701,7 +2733,7 @@ mod tests {
}
// reset
stake_keyed_account.account.lamports = stake_lamports;
stake_keyed_account.account.borrow_mut().lamports = stake_lamports;
}
}
@ -2792,7 +2824,7 @@ mod tests {
fn test_authorize_delegated_stake() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account = Account::new_data_with_space(
let mut stake_account = Account::new_ref_data_with_space(
stake_lamports,
&StakeState::Initialized(Meta::auto(&stake_pubkey)),
std::mem::size_of::<StakeState>(),
@ -2803,8 +2835,12 @@ mod tests {
let mut clock = Clock::default();
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_account = RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
@ -2823,7 +2859,8 @@ mod tests {
),
Ok(())
);
let authorized = StakeState::authorized_from(&stake_keyed_account.account).unwrap();
let authorized =
StakeState::authorized_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap();
assert_eq!(authorized.staker, new_staker_pubkey);
let other_pubkey = Pubkey::new_rand();
@ -2834,8 +2871,12 @@ mod tests {
let new_voter_pubkey = Pubkey::new_rand();
let vote_state = VoteState::default();
let mut new_vote_account =
vote_state::create_account(&new_voter_pubkey, &Pubkey::new_rand(), 0, 100);
let mut new_vote_account = RefCell::new(vote_state::create_account(
&new_voter_pubkey,
&Pubkey::new_rand(),
0,
100,
));
let mut new_vote_keyed_account =
KeyedAccount::new(&new_voter_pubkey, false, &mut new_vote_account);
new_vote_keyed_account.set_state(&vote_state).unwrap();
@ -2864,7 +2905,8 @@ mod tests {
),
Ok(())
);
let stake = StakeState::stake_from(&stake_keyed_account.account).unwrap();
let stake =
StakeState::stake_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap();
assert_eq!(stake.delegation.voter_pubkey, new_voter_pubkey);
// Test another staking action

View File

@ -421,13 +421,13 @@ fn check_redeemable(
owner: &mut StorageAccount,
) -> Result<(), InstructionError> {
let rewards = (credits.redeemable as f64 * storage_point_value) as u64;
if rewards_pool.account.lamports < rewards {
if rewards_pool.lamports()? < rewards {
Err(InstructionError::CustomError(
StorageError::RewardPoolDepleted as u32,
))
} else {
if rewards >= 1 {
rewards_pool.account.lamports -= rewards;
rewards_pool.try_account_ref_mut()?.lamports -= rewards;
owner.account.lamports += rewards;
//clear credits
credits.redeemable = 0;
@ -503,7 +503,7 @@ fn count_valid_proofs(
mod tests {
use super::*;
use crate::{id, rewards_pools};
use std::collections::BTreeMap;
use std::{cell::RefCell, collections::BTreeMap};
#[test]
fn test_account_data() {
@ -617,7 +617,7 @@ mod tests {
lamports: 1,
..Account::default()
};
let mut rewards_pool = create_rewards_pool();
let mut rewards_pool = RefCell::new(create_rewards_pool());
let pool_id = rewards_pools::id();
let mut keyed_pool_account = KeyedAccount::new(&pool_id, false, &mut rewards_pool);
let mut owner = StorageAccount {
@ -626,7 +626,7 @@ mod tests {
};
// check that redeeming from depleted pools fails
keyed_pool_account.account.lamports = 0;
keyed_pool_account.account.borrow_mut().lamports = 0;
assert_eq!(
check_redeemable(&mut credits, 1.0, &mut keyed_pool_account, &mut owner),
Err(InstructionError::CustomError(
@ -635,7 +635,7 @@ mod tests {
);
assert_eq!(owner.account.lamports, 1);
keyed_pool_account.account.lamports = 200;
keyed_pool_account.account.borrow_mut().lamports = 200;
assert_eq!(
check_redeemable(&mut credits, 1.0, &mut keyed_pool_account, &mut owner),
Ok(())

View File

@ -19,7 +19,8 @@ pub fn process_instruction(
let (me, rest) = keyed_accounts.split_at_mut(1);
let me_unsigned = me[0].signer_key().is_none();
let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me[0].account);
let mut me_account = me[0].try_account_ref_mut()?;
let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me_account);
match limited_deserialize(data)? {
StorageInstruction::InitializeStorage {
@ -68,7 +69,8 @@ pub fn process_instruction(
let rewards = Rewards::from_keyed_account(&rewards[0])?;
let clock = Clock::from_keyed_account(&clock[0])?;
let mut owner = StorageAccount::new(*owner[0].unsigned_key(), &mut owner[0].account);
let mut owner_account = owner[0].try_account_ref_mut()?;
let mut owner = StorageAccount::new(*owner[0].unsigned_key(), &mut owner_account);
storage_account.claim_storage_reward(&mut rewards_pools[0], clock, rewards, &mut owner)
}
@ -84,12 +86,16 @@ pub fn process_instruction(
}
let me_id = storage_account.id;
let clock = Clock::from_keyed_account(&clock[0])?;
let mut rest: Vec<_> = rest
let mut rest = rest
.iter()
.map(|keyed_account| Ok((keyed_account, keyed_account.try_account_ref_mut()?)))
.collect::<Result<Vec<_>, InstructionError>>()?;
let mut rest = rest
.iter_mut()
.map(|keyed_account| {
StorageAccount::new(*keyed_account.unsigned_key(), &mut keyed_account.account)
.map(|(keyed_account, account_ref)| {
StorageAccount::new(*keyed_account.unsigned_key(), account_ref)
})
.collect();
.collect::<Vec<_>>();
storage_account.proof_validation(&me_id, clock, segment, proofs, &mut rest)
}
}
@ -117,15 +123,20 @@ mod tests {
Sysvar,
},
};
use std::cell::RefCell;
fn test_instruction(
ix: &Instruction,
program_accounts: &mut [Account],
) -> Result<(), InstructionError> {
let program_accounts: Vec<_> = program_accounts
.iter()
.map(|account| RefCell::new(account.clone()))
.collect();
let mut keyed_accounts: Vec<_> = ix
.accounts
.iter()
.zip(program_accounts.iter_mut())
.zip(program_accounts.iter())
.map(|(account_meta, account)| {
KeyedAccount::new(&account_meta.pubkey, account_meta.is_signer, account)
})
@ -175,7 +186,7 @@ mod tests {
#[test]
fn test_storage_tx() {
let pubkey = Pubkey::new_rand();
let mut accounts = [(pubkey, Account::default())];
let mut accounts = [(&pubkey, &RefCell::new(Account::default()))];
let mut keyed_accounts = create_keyed_accounts(&mut accounts);
assert!(process_instruction(&id(), &mut keyed_accounts, &[]).is_err());
}
@ -185,8 +196,8 @@ mod tests {
let pubkey = Pubkey::new_rand();
let clock_id = clock::id();
let mut keyed_accounts = Vec::new();
let mut user_account = Account::default();
let mut clock_account = Clock::default().create_account(1);
let mut user_account = RefCell::new(Account::default());
let mut clock_account = RefCell::new(Clock::default().create_account(1));
keyed_accounts.push(KeyedAccount::new(&pubkey, true, &mut user_account));
keyed_accounts.push(KeyedAccount::new(&clock_id, false, &mut clock_account));

View File

@ -12,12 +12,13 @@ use solana_sdk::{
instruction_processor_utils::{limited_deserialize, next_keyed_account},
pubkey::Pubkey,
};
use std::cell::RefMut;
fn verify_date_account(
keyed_account: &mut KeyedAccount,
expected_pubkey: &Pubkey,
) -> Result<Date<Utc>, InstructionError> {
if keyed_account.account.owner != solana_config_program::id() {
if keyed_account.owner()? != solana_config_program::id() {
return Err(InstructionError::IncorrectProgramId);
}
@ -34,18 +35,18 @@ fn verify_date_account(
fn verify_account<'a>(
keyed_account: &'a mut KeyedAccount,
expected_pubkey: &Pubkey,
) -> Result<&'a mut Account, InstructionError> {
) -> Result<RefMut<'a, Account>, InstructionError> {
if keyed_account.unsigned_key() != expected_pubkey {
return Err(VestError::Unauthorized.into());
}
Ok(keyed_account.account)
keyed_account.try_account_ref_mut()
}
fn verify_signed_account<'a>(
keyed_account: &'a mut KeyedAccount,
expected_pubkey: &Pubkey,
) -> Result<&'a mut Account, InstructionError> {
) -> Result<RefMut<'a, Account>, InstructionError> {
if keyed_account.signer_key().is_none() {
return Err(InstructionError::MissingRequiredSignature);
}
@ -59,7 +60,7 @@ pub fn process_instruction(
data: &[u8],
) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.account;
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?;
let instruction = limited_deserialize(data)?;
@ -104,11 +105,11 @@ pub fn process_instruction(
next_keyed_account(keyed_accounts_iter)?,
&vest_state.date_pubkey,
)?;
let payee_account = verify_account(
let mut payee_account = verify_account(
next_keyed_account(keyed_accounts_iter)?,
&vest_state.payee_pubkey,
)?;
vest_state.redeem_tokens(contract_account, current_date, payee_account);
vest_state.redeem_tokens(contract_account, current_date, &mut payee_account);
}
VestInstruction::Terminate | VestInstruction::Renege(_) => {
let lamports = if let VestInstruction::Renege(lamports) = instruction {
@ -121,12 +122,12 @@ pub fn process_instruction(
&vest_state.terminator_pubkey,
)?;
let payee_keyed_account = keyed_accounts_iter.next();
let payee_account = if let Some(payee_keyed_account) = payee_keyed_account {
&mut payee_keyed_account.account
let mut payee_account = if let Some(payee_keyed_account) = payee_keyed_account {
payee_keyed_account.try_account_ref_mut()?
} else {
terminator_account
};
vest_state.renege(contract_account, payee_account, lamports);
vest_state.renege(contract_account, &mut payee_account, lamports);
}
VestInstruction::VestAll => {
verify_signed_account(
@ -264,7 +265,7 @@ mod tests {
fn test_verify_account_unauthorized() {
// Ensure client can't sneak in with an untrusted date account.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &solana_config_program::id());
let mut account = Account::new_ref(1, 0, &solana_config_program::id());
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account);
let mallory_pubkey = Pubkey::new_rand(); // <-- Attack! Not the expected account.
@ -278,7 +279,7 @@ mod tests {
fn test_verify_signed_account_missing_signature() {
// Ensure client can't sneak in with an unsigned account.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &solana_config_program::id());
let mut account = Account::new_ref(1, 0, &solana_config_program::id());
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account); // <-- Attack! Unsigned transaction.
assert_eq!(
@ -291,7 +292,7 @@ mod tests {
fn test_verify_date_account_incorrect_program_id() {
// Ensure client can't sneak in with a non-Config account.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &id()); // <-- Attack! Pass Vest account where Config account is expected.
let mut account = Account::new_ref(1, 0, &id()); // <-- Attack! Pass Vest account where Config account is expected.
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account);
assert_eq!(
verify_date_account(&mut keyed_account, &date_pubkey).unwrap_err(),
@ -303,7 +304,7 @@ mod tests {
fn test_verify_date_account_uninitialized_config() {
// Ensure no panic when `get_config_data()` returns an error.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 0, &solana_config_program::id()); // <-- Attack! Zero space.
let mut account = Account::new_ref(1, 0, &solana_config_program::id()); // <-- Attack! Zero space.
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account);
assert_eq!(
verify_date_account(&mut keyed_account, &date_pubkey).unwrap_err(),
@ -315,7 +316,7 @@ mod tests {
fn test_verify_date_account_invalid_date_config() {
// Ensure no panic when `deserialize::<DateConfig>()` returns an error.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 1, &solana_config_program::id()); // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let mut account = Account::new_ref(1, 1, &solana_config_program::id()); // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account);
assert_eq!(
verify_date_account(&mut keyed_account, &date_pubkey).unwrap_err(),
@ -327,7 +328,7 @@ mod tests {
fn test_verify_date_account_deserialize() {
// Ensure no panic when `deserialize::<DateConfig>()` returns an error.
let date_pubkey = Pubkey::new_rand();
let mut account = Account::new(1, 1, &solana_config_program::id()); // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let mut account = Account::new_ref(1, 1, &solana_config_program::id()); // Attack! 1 byte, enough to sneak by `get_config_data()`, but not DateConfig deserialize.
let mut keyed_account = KeyedAccount::new(&date_pubkey, false, &mut account);
assert_eq!(
verify_date_account(&mut keyed_account, &date_pubkey).unwrap_err(),

View File

@ -228,8 +228,8 @@ pub fn process_instruction(
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::account::Account;
use solana_sdk::rent::Rent;
use solana_sdk::{account::Account, rent::Rent};
use std::cell::RefCell;
// these are for 100% coverage in this file
#[test]
@ -245,7 +245,7 @@ mod tests {
.accounts
.iter()
.map(|meta| {
if sysvar::clock::check_id(&meta.pubkey) {
RefCell::new(if sysvar::clock::check_id(&meta.pubkey) {
Clock::default().create_account(1)
} else if sysvar::slot_hashes::check_id(&meta.pubkey) {
SlotHashes::default().create_account(1)
@ -253,12 +253,12 @@ mod tests {
Rent::free().create_account(1)
} else {
Account::default()
}
})
})
.collect();
for _ in 0..instruction.accounts.len() {
accounts.push(Account::default());
accounts.push(RefCell::new(Account::default()));
}
{
let mut keyed_accounts: Vec<_> = instruction

View File

@ -501,11 +501,11 @@ pub fn withdraw(
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
if vote_account.account.lamports < lamports {
if vote_account.lamports()? < lamports {
return Err(InstructionError::InsufficientFunds);
}
vote_account.account.lamports -= lamports;
to_account.account.lamports += lamports;
vote_account.try_account_ref_mut()?.lamports -= lamports;
to_account.try_account_ref_mut()?.lamports += lamports;
Ok(())
}
@ -585,6 +585,7 @@ mod tests {
hash::hash,
instruction_processor_utils::next_keyed_account,
};
use std::cell::RefCell;
const MAX_RECENT_VOTES: usize = 16;
@ -605,7 +606,7 @@ mod tests {
#[test]
fn test_initialize_vote_account() {
let vote_account_pubkey = Pubkey::new_rand();
let mut vote_account = Account::new(100, VoteState::size_of(), &id());
let mut vote_account = Account::new_ref(100, VoteState::size_of(), &id());
let node_pubkey = Pubkey::new_rand();
@ -637,17 +638,22 @@ mod tests {
assert_eq!(res, Err(InstructionError::AccountAlreadyInitialized));
}
fn create_test_account() -> (Pubkey, Account) {
fn create_test_account() -> (Pubkey, RefCell<Account>) {
let vote_pubkey = Pubkey::new_rand();
(
vote_pubkey,
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100),
RefCell::new(vote_state::create_account(
&vote_pubkey,
&Pubkey::new_rand(),
0,
100,
)),
)
}
fn simulate_process_vote(
vote_pubkey: &Pubkey,
vote_account: &mut Account,
vote_account: &mut RefCell<Account>,
vote: &Vote,
slot_hashes: &[SlotHash],
epoch: Epoch,
@ -664,13 +670,13 @@ mod tests {
&vote.clone(),
&signers,
)?;
vote_account.state()
vote_account.borrow().state()
}
/// exercises all the keyed accounts stuff
fn simulate_process_vote_unchecked(
vote_pubkey: &Pubkey,
vote_account: &mut Account,
vote_account: &mut RefCell<Account>,
vote: &Vote,
) -> Result<VoteState, InstructionError> {
simulate_process_vote(
@ -698,7 +704,7 @@ mod tests {
fn test_voter_registration() {
let (vote_pubkey, vote_account) = create_test_account();
let vote_state: VoteState = vote_account.state().unwrap();
let vote_state: VoteState = vote_account.borrow().state().unwrap();
assert_eq!(vote_state.authorized_voter, vote_pubkey);
assert!(vote_state.votes.is_empty());
}
@ -759,14 +765,14 @@ mod tests {
let signers = get_signers(keyed_accounts);
let res = update_node(&mut keyed_accounts[0], &node_pubkey, &signers);
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
let vote_state: VoteState = vote_account.state().unwrap();
let vote_state: VoteState = vote_account.borrow().state().unwrap();
assert!(vote_state.node_pubkey != node_pubkey);
let keyed_accounts = &mut [KeyedAccount::new(&vote_pubkey, true, &mut vote_account)];
let signers = get_signers(keyed_accounts);
let res = update_node(&mut keyed_accounts[0], &node_pubkey, &signers);
assert_eq!(res, Ok(()));
let vote_state: VoteState = vote_account.state().unwrap();
let vote_state: VoteState = vote_account.borrow().state().unwrap();
assert_eq!(vote_state.node_pubkey, node_pubkey);
}
@ -839,7 +845,7 @@ mod tests {
assert_eq!(res, Ok(()));
// verify authorized_voter_pubkey can authorize authorized_voter_pubkey ;)
let mut authorized_voter_account = Account::default();
let mut authorized_voter_account = RefCell::new(Account::default());
let keyed_accounts = &mut [
KeyedAccount::new(&vote_pubkey, false, &mut vote_account),
KeyedAccount::new(
@ -873,7 +879,7 @@ mod tests {
assert_eq!(res, Ok(()));
// verify authorized_withdrawer can authorize authorized_withdrawer ;)
let mut withdrawer_account = Account::default();
let mut withdrawer_account = RefCell::new(Account::default());
let keyed_accounts = &mut [
KeyedAccount::new(&vote_pubkey, false, &mut vote_account),
KeyedAccount::new(&authorized_withdrawer_pubkey, true, &mut withdrawer_account),
@ -902,7 +908,7 @@ mod tests {
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
// signed by authorized voter
let mut authorized_voter_account = Account::default();
let mut authorized_voter_account = RefCell::new(Account::default());
let keyed_accounts = &mut [
KeyedAccount::new(&vote_pubkey, false, &mut vote_account),
KeyedAccount::new(
@ -926,7 +932,7 @@ mod tests {
#[test]
fn test_vote_without_initialization() {
let vote_pubkey = Pubkey::new_rand();
let mut vote_account = Account::new(100, VoteState::size_of(), &id());
let mut vote_account = RefCell::new(Account::new(100, VoteState::size_of(), &id()));
let res = simulate_process_vote_unchecked(
&vote_pubkey,
@ -940,7 +946,7 @@ mod tests {
fn test_vote_lockout() {
let (_vote_pubkey, vote_account) = create_test_account();
let mut vote_state: VoteState = vote_account.state().unwrap();
let mut vote_state: VoteState = vote_account.borrow().state().unwrap();
for i in 0..(MAX_LOCKOUT_HISTORY + 1) {
vote_state.process_slot_vote_unchecked((INITIAL_LOCKOUT as usize * i) as u64);
@ -1254,7 +1260,11 @@ mod tests {
let res = withdraw(
&mut keyed_accounts[0],
0,
&mut KeyedAccount::new(&Pubkey::new_rand(), false, &mut Account::default()),
&mut KeyedAccount::new(
&Pubkey::new_rand(),
false,
&mut RefCell::new(Account::default()),
),
&signers,
);
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
@ -1265,14 +1275,18 @@ mod tests {
let res = withdraw(
&mut keyed_accounts[0],
101,
&mut KeyedAccount::new(&Pubkey::new_rand(), false, &mut Account::default()),
&mut KeyedAccount::new(
&Pubkey::new_rand(),
false,
&mut RefCell::new(Account::default()),
),
&signers,
);
assert_eq!(res, Err(InstructionError::InsufficientFunds));
// all good
let mut to_account = Account::default();
let lamports = vote_account.lamports;
let mut to_account = RefCell::new(Account::default());
let lamports = vote_account.borrow().lamports;
let keyed_accounts = &mut [KeyedAccount::new(&vote_pubkey, true, &mut vote_account)];
let signers = get_signers(keyed_accounts);
let res = withdraw(
@ -1282,11 +1296,11 @@ mod tests {
&signers,
);
assert_eq!(res, Ok(()));
assert_eq!(vote_account.lamports, 0);
assert_eq!(to_account.lamports, lamports);
assert_eq!(vote_account.borrow().lamports, 0);
assert_eq!(to_account.borrow().lamports, lamports);
// reset balance, verify that authorized_withdrawer works
vote_account.lamports = lamports;
vote_account.borrow_mut().lamports = lamports;
// authorize authorized_withdrawer
let authorized_withdrawer_pubkey = Pubkey::new_rand();
@ -1302,7 +1316,7 @@ mod tests {
assert_eq!(res, Ok(()));
// withdraw using authorized_withdrawer to authorized_withdrawer's account
let mut withdrawer_account = Account::default();
let mut withdrawer_account = RefCell::new(Account::default());
let keyed_accounts = &mut [
KeyedAccount::new(&vote_pubkey, false, &mut vote_account),
KeyedAccount::new(&authorized_withdrawer_pubkey, true, &mut withdrawer_account),
@ -1318,8 +1332,8 @@ mod tests {
&signers,
);
assert_eq!(res, Ok(()));
assert_eq!(vote_account.lamports, 0);
assert_eq!(withdrawer_account.lamports, lamports);
assert_eq!(vote_account.borrow().lamports, 0);
assert_eq!(withdrawer_account.borrow().lamports, lamports);
}
#[test]