Allow the same account to be passed multiple times to a single instruction (#7795)
This commit is contained in:
parent
d854e90c23
commit
023074650f
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ¶meter_bytes);
|
||||
deserialize_parameters(parameter_accounts, ¶meter_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, ¶meter_account));
|
||||
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account));
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
process_instruction(&program_id, &mut keyed_accounts, &vec![])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -21,6 +21,14 @@ fn deposit_many(bank: &Bank, pubkeys: &mut Vec<Pubkey>, num: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_has_duplicates(bencher: &mut Bencher) {
|
||||
bencher.iter(|| {
|
||||
let data = test::black_box([1, 2, 3]);
|
||||
assert!(!Accounts::has_duplicates(&data));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn test_accounts_create(bencher: &mut Bencher) {
|
||||
let (genesis_config, _) = create_genesis_config(10_000);
|
||||
|
|
|
@ -7,14 +7,6 @@ use solana_runtime::message_processor::*;
|
|||
use solana_sdk::{account::Account, pubkey::Pubkey};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_has_duplicates(bencher: &mut Bencher) {
|
||||
bencher.iter(|| {
|
||||
let data = test::black_box([1, 2, 3]);
|
||||
assert!(!has_duplicates(&data));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_verify_account_changes_data(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::accounts_index::AccountsIndex;
|
|||
use crate::append_vec::StoredAccount;
|
||||
use crate::bank::{HashAgeKind, TransactionProcessResult};
|
||||
use crate::blockhash_queue::BlockhashQueue;
|
||||
use crate::message_processor::has_duplicates;
|
||||
use crate::nonce_utils::prepare_if_nonce_account;
|
||||
use crate::rent_collector::RentCollector;
|
||||
use crate::system_instruction_processor::{get_system_account_kind, SystemAccountKind};
|
||||
|
@ -87,6 +86,19 @@ impl Accounts {
|
|||
.accounts_from_stream(stream, local_paths, append_vecs_path)
|
||||
}
|
||||
|
||||
/// Return true if the slice has any duplicate elements
|
||||
pub fn has_duplicates<T: PartialEq>(xs: &[T]) -> bool {
|
||||
// Note: This is an O(n^2) algorithm, but requires no heap allocations. The benchmark
|
||||
// `bench_has_duplicates` in benches/message_processor.rs shows that this implementation is
|
||||
// ~50 times faster than using HashSet for very short slices.
|
||||
for i in 1..xs.len() {
|
||||
if xs[i..].contains(&xs[i - 1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn load_tx_accounts(
|
||||
&self,
|
||||
storage: &AccountStorage,
|
||||
|
@ -103,7 +115,7 @@ impl Accounts {
|
|||
Err(TransactionError::MissingSignatureForFee)
|
||||
} else {
|
||||
// Check for unique account keys
|
||||
if has_duplicates(&message.account_keys) {
|
||||
if Self::has_duplicates(&message.account_keys) {
|
||||
error_counters.account_loaded_twice += 1;
|
||||
return Err(TransactionError::AccountLoadedTwice);
|
||||
}
|
||||
|
@ -1634,4 +1646,10 @@ mod tests {
|
|||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_duplicates() {
|
||||
assert!(!Accounts::has_duplicates(&[1, 2]));
|
||||
assert!(Accounts::has_duplicates(&[1, 2, 1]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! on behalf of the caller, and a low-level API for when they have
|
||||
//! already been signed and verified.
|
||||
use crate::{
|
||||
accounts::{Accounts, TransactionLoadResult},
|
||||
accounts::{Accounts, TransactionAccounts, TransactionLoadResult, TransactionLoaders},
|
||||
accounts_db::{AccountStorageEntry, AccountsDBSerialize, AppendVecId, ErrorCounters},
|
||||
blockhash_queue::BlockhashQueue,
|
||||
message_processor::{MessageProcessor, ProcessInstruction},
|
||||
|
@ -51,9 +51,11 @@ use solana_sdk::{
|
|||
use solana_stake_program::stake_state::Delegation;
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
io::{BufReader, Cursor, Error as IOError, Read},
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
sync::{Arc, RwLock, RwLockReadGuard},
|
||||
};
|
||||
|
@ -64,6 +66,8 @@ pub const MAX_SNAPSHOT_DATA_FILE_SIZE: u64 = 32 * 1024 * 1024 * 1024; // 32 GiB
|
|||
pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
|
||||
|
||||
type BankStatusCache = StatusCache<Result<()>>;
|
||||
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
|
||||
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<Account>)>>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BankRc {
|
||||
|
@ -1167,6 +1171,48 @@ impl Bank {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts Accounts into RefCell<Account>, this involves moving
|
||||
/// ownership by draining the source
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn into_refcells(
|
||||
accounts: &mut TransactionAccounts,
|
||||
loaders: &mut TransactionLoaders,
|
||||
) -> (TransactionAccountRefCells, TransactionLoaderRefCells) {
|
||||
let account_refcells: Vec<_> = accounts
|
||||
.drain(..)
|
||||
.map(|account| Rc::new(RefCell::new(account)))
|
||||
.collect();
|
||||
let loader_refcells: Vec<Vec<_>> = loaders
|
||||
.iter_mut()
|
||||
.map(|v| {
|
||||
v.drain(..)
|
||||
.map(|(pubkey, account)| (pubkey, RefCell::new(account)))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
(account_refcells, loader_refcells)
|
||||
}
|
||||
|
||||
/// Converts back from RefCell<Account> to Account, this involves moving
|
||||
/// ownership by draining the sources
|
||||
fn from_refcells(
|
||||
accounts: &mut TransactionAccounts,
|
||||
loaders: &mut TransactionLoaders,
|
||||
mut account_refcells: TransactionAccountRefCells,
|
||||
loader_refcells: TransactionLoaderRefCells,
|
||||
) {
|
||||
account_refcells.drain(..).for_each(|account_refcell| {
|
||||
accounts.push(Rc::try_unwrap(account_refcell).unwrap().into_inner())
|
||||
});
|
||||
loaders
|
||||
.iter_mut()
|
||||
.zip(loader_refcells)
|
||||
.for_each(|(ls, mut lrcs)| {
|
||||
lrcs.drain(..)
|
||||
.for_each(|(pubkey, lrc)| ls.push((pubkey, lrc.into_inner())))
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn load_and_execute_transactions(
|
||||
&self,
|
||||
|
@ -1222,9 +1268,18 @@ impl Bank {
|
|||
(Err(e), hash_age_kind) => (Err(e.clone()), hash_age_kind.clone()),
|
||||
(Ok((accounts, loaders, _rents)), hash_age_kind) => {
|
||||
signature_count += u64::from(tx.message().header.num_required_signatures);
|
||||
let process_result =
|
||||
self.message_processor
|
||||
.process_message(tx.message(), loaders, accounts);
|
||||
|
||||
let (mut account_refcells, mut loader_refcells) =
|
||||
Self::into_refcells(accounts, loaders);
|
||||
|
||||
let process_result = self.message_processor.process_message(
|
||||
tx.message(),
|
||||
&mut loader_refcells,
|
||||
&mut account_refcells,
|
||||
);
|
||||
|
||||
Self::from_refcells(accounts, loaders, account_refcells, loader_refcells);
|
||||
|
||||
if let Err(TransactionError::InstructionError(_, _)) = &process_result {
|
||||
error_counters.instruction_error += 1;
|
||||
}
|
||||
|
@ -2285,8 +2340,8 @@ mod tests {
|
|||
if let Ok(instruction) = bincode::deserialize(data) {
|
||||
match instruction {
|
||||
MockInstruction::Deduction => {
|
||||
keyed_accounts[1].account.lamports += 1;
|
||||
keyed_accounts[2].account.lamports -= 1;
|
||||
keyed_accounts[1].account.borrow_mut().lamports += 1;
|
||||
keyed_accounts[2].account.borrow_mut().lamports -= 1;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -2873,8 +2928,8 @@ mod tests {
|
|||
|
||||
// set up stakes, vote, and storage accounts
|
||||
bank.store_account(&stake.0, &stake.1);
|
||||
bank.store_account(&validator_id, &validator_account);
|
||||
bank.store_account(&archiver_id, &archiver_account);
|
||||
bank.store_account(&validator_id, &validator_account.borrow());
|
||||
bank.store_account(&archiver_id, &archiver_account.borrow());
|
||||
|
||||
// generate some rewards
|
||||
let mut vote_state = VoteState::from(&vote_account).unwrap();
|
||||
|
@ -5136,4 +5191,56 @@ mod tests {
|
|||
assert_eq!(transaction_balances_set.pre_balances[2], vec![9, 0, 1]);
|
||||
assert_eq!(transaction_balances_set.post_balances[2], vec![8, 0, 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_with_duplicate_accounts_in_instruction() {
|
||||
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
|
||||
fn mock_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
data: &[u8],
|
||||
) -> result::Result<(), InstructionError> {
|
||||
let lamports = data[0] as u64;
|
||||
{
|
||||
let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
|
||||
let mut dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
dup_account.lamports -= lamports;
|
||||
to_account.lamports += lamports;
|
||||
}
|
||||
keyed_accounts[0].try_account_ref_mut()?.lamports -= lamports;
|
||||
keyed_accounts[1].try_account_ref_mut()?.lamports += lamports;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
||||
bank.add_instruction_processor(mock_program_id, mock_process_instruction);
|
||||
|
||||
let from_pubkey = Pubkey::new_rand();
|
||||
let to_pubkey = Pubkey::new_rand();
|
||||
let dup_pubkey = from_pubkey.clone();
|
||||
let from_account = Account::new(100, 1, &mock_program_id);
|
||||
let to_account = Account::new(0, 1, &mock_program_id);
|
||||
bank.store_account(&from_pubkey, &from_account);
|
||||
bank.store_account(&to_pubkey, &to_account);
|
||||
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(from_pubkey, false),
|
||||
AccountMeta::new(to_pubkey, false),
|
||||
AccountMeta::new(dup_pubkey, false),
|
||||
];
|
||||
let instruction = Instruction::new(mock_program_id, &10, account_metas);
|
||||
let tx = Transaction::new_signed_with_payer(
|
||||
vec![instruction],
|
||||
Some(&mint_keypair.pubkey()),
|
||||
&[&mint_keypair],
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
|
||||
let result = bank.process_transaction(&tx);
|
||||
assert_eq!(result, Ok(()));
|
||||
assert_eq!(bank.get_balance(&from_pubkey), 80);
|
||||
assert_eq!(bank.get_balance(&to_pubkey), 20);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ use solana_sdk::message::Message;
|
|||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::system_program;
|
||||
use solana_sdk::transaction::TransactionError;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[cfg(unix)]
|
||||
|
@ -17,44 +19,6 @@ use libloading::os::unix::*;
|
|||
#[cfg(windows)]
|
||||
use libloading::os::windows::*;
|
||||
|
||||
/// Return true if the slice has any duplicate elements
|
||||
pub fn has_duplicates<T: PartialEq>(xs: &[T]) -> bool {
|
||||
// Note: This is an O(n^2) algorithm, but requires no heap allocations. The benchmark
|
||||
// `bench_has_duplicates` in benches/message_processor.rs shows that this implementation is
|
||||
// ~50 times faster than using HashSet for very short slices.
|
||||
for i in 1..xs.len() {
|
||||
if xs[i..].contains(&xs[i - 1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Get mut references to a subset of elements.
|
||||
fn get_subset_unchecked_mut<'a, T>(
|
||||
xs: &'a mut [T],
|
||||
indexes: &[u8],
|
||||
) -> Result<Vec<&'a mut T>, InstructionError> {
|
||||
// Since the compiler doesn't know the indexes are unique, dereferencing
|
||||
// multiple mut elements is assumed to be unsafe. If, however, all
|
||||
// indexes are unique, it's perfectly safe. The returned elements will share
|
||||
// the liftime of the input slice.
|
||||
|
||||
// Make certain there are no duplicate indexes. If there are, return an error
|
||||
// because we can't return multiple mut references to the same element.
|
||||
if has_duplicates(indexes) {
|
||||
return Err(InstructionError::DuplicateAccountIndex);
|
||||
}
|
||||
|
||||
Ok(indexes
|
||||
.iter()
|
||||
.map(|i| {
|
||||
let ptr = &mut xs[*i as usize] as *mut T;
|
||||
unsafe { &mut *ptr }
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
// The relevant state of an account before an Instruction executes, used
|
||||
// to verify account integrity after the Instruction completes
|
||||
pub struct PreInstructionAccount {
|
||||
|
@ -204,8 +168,8 @@ impl MessageProcessor {
|
|||
&self,
|
||||
message: &Message,
|
||||
instruction: &CompiledInstruction,
|
||||
executable_accounts: &mut [(Pubkey, Account)],
|
||||
program_accounts: &mut [&mut Account],
|
||||
executable_accounts: &mut [(Pubkey, RefCell<Account>)],
|
||||
program_accounts: &mut [Rc<RefCell<Account>>],
|
||||
) -> Result<(), InstructionError> {
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
let mut keyed_accounts = create_keyed_readonly_accounts(executable_accounts);
|
||||
|
@ -234,7 +198,7 @@ impl MessageProcessor {
|
|||
keyed_accounts.append(&mut keyed_accounts2);
|
||||
|
||||
assert!(
|
||||
keyed_accounts[0].account.executable,
|
||||
keyed_accounts[0].try_account_ref()?.executable,
|
||||
"loader not executable"
|
||||
);
|
||||
|
||||
|
@ -257,8 +221,38 @@ impl MessageProcessor {
|
|||
)
|
||||
}
|
||||
|
||||
fn sum_account_lamports(accounts: &mut [&mut Account]) -> u128 {
|
||||
accounts.iter().map(|a| u128::from(a.lamports)).sum()
|
||||
pub fn verify_account_references(
|
||||
executable_accounts: &mut [(Pubkey, RefCell<Account>)],
|
||||
program_accounts: &mut [Rc<RefCell<Account>>],
|
||||
) -> Result<(), InstructionError> {
|
||||
for account in program_accounts.iter() {
|
||||
account
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
||||
}
|
||||
for (_, account) in executable_accounts.iter() {
|
||||
account
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sum_account_lamports(accounts: &[Rc<RefCell<Account>>]) -> u128 {
|
||||
// Note: This is an O(n^2) algorithm,
|
||||
// but performed on a very small slice and requires no heap allocations
|
||||
accounts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
for account in accounts.iter().skip(i + 1) {
|
||||
if Rc::ptr_eq(a, account) {
|
||||
return 0; // don't double count duplicates
|
||||
}
|
||||
}
|
||||
u128::from(a.borrow().lamports)
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
/// Execute an instruction
|
||||
|
@ -269,8 +263,8 @@ impl MessageProcessor {
|
|||
&self,
|
||||
message: &Message,
|
||||
instruction: &CompiledInstruction,
|
||||
executable_accounts: &mut [(Pubkey, Account)],
|
||||
program_accounts: &mut [&mut Account],
|
||||
executable_accounts: &mut [(Pubkey, RefCell<Account>)],
|
||||
program_accounts: &mut [Rc<RefCell<Account>>],
|
||||
) -> Result<(), InstructionError> {
|
||||
assert_eq!(instruction.accounts.len(), program_accounts.len());
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
|
@ -280,8 +274,9 @@ impl MessageProcessor {
|
|||
.enumerate()
|
||||
.map(|(i, account)| {
|
||||
let is_writable = message.is_writable(instruction.accounts[i] as usize);
|
||||
let account = account.borrow();
|
||||
PreInstructionAccount::new(
|
||||
account,
|
||||
&account,
|
||||
is_writable,
|
||||
need_account_data_checked(&account.owner, program_id, is_writable),
|
||||
)
|
||||
|
@ -292,11 +287,16 @@ impl MessageProcessor {
|
|||
|
||||
self.process_instruction(message, instruction, executable_accounts, program_accounts)?;
|
||||
|
||||
// Verify all accounts have zero outstanding refs
|
||||
Self::verify_account_references(executable_accounts, program_accounts)?;
|
||||
// Verify the instruction
|
||||
for (pre_account, post_account) in pre_accounts.iter().zip(program_accounts.iter()) {
|
||||
verify_account_changes(&program_id, pre_account, post_account)?;
|
||||
let post_account = post_account
|
||||
.try_borrow()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)?;
|
||||
verify_account_changes(&program_id, pre_account, &post_account)?;
|
||||
}
|
||||
// The total sum of all the lamports in all the accounts cannot change.
|
||||
// Verify total sum of all the lamports did not change
|
||||
let post_total = Self::sum_account_lamports(program_accounts);
|
||||
if pre_total != post_total {
|
||||
return Err(InstructionError::UnbalancedInstruction);
|
||||
|
@ -310,19 +310,24 @@ impl MessageProcessor {
|
|||
pub fn process_message(
|
||||
&self,
|
||||
message: &Message,
|
||||
loaders: &mut [Vec<(Pubkey, Account)>],
|
||||
accounts: &mut [Account],
|
||||
loaders: &mut [Vec<(Pubkey, RefCell<Account>)>],
|
||||
accounts: &mut [Rc<RefCell<Account>>],
|
||||
) -> Result<(), TransactionError> {
|
||||
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
||||
let executable_index = message
|
||||
.program_position(instruction.program_id_index as usize)
|
||||
.ok_or(TransactionError::InvalidAccountIndex)?;
|
||||
let executable_accounts = &mut loaders[executable_index];
|
||||
let mut program_accounts = get_subset_unchecked_mut(accounts, &instruction.accounts)
|
||||
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
||||
// TODO: `get_subset_unchecked_mut` panics on an index out of bounds if an executable
|
||||
|
||||
// TODO: panics on an index out of bounds if an executable
|
||||
// account is also included as a regular account for an instruction, because the
|
||||
// executable account is not passed in as part of the accounts slice
|
||||
let mut program_accounts: Vec<_> = instruction
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|i| accounts[*i as usize].clone())
|
||||
.collect();
|
||||
|
||||
self.execute_instruction(
|
||||
message,
|
||||
instruction,
|
||||
|
@ -373,37 +378,72 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_duplicates() {
|
||||
assert!(!has_duplicates(&[1, 2]));
|
||||
assert!(has_duplicates(&[1, 2, 1]));
|
||||
fn test_verify_account_references() {
|
||||
let mut executable_accounts = vec![(Pubkey::new_rand(), RefCell::new(Account::default()))];
|
||||
let mut program_accounts = vec![Rc::new(RefCell::new(Account::default()))];
|
||||
|
||||
assert!(MessageProcessor::verify_account_references(
|
||||
&mut executable_accounts,
|
||||
&mut program_accounts,
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
let cloned = program_accounts[0].clone();
|
||||
let _borrowed = cloned.borrow();
|
||||
assert_eq!(
|
||||
MessageProcessor::verify_account_references(
|
||||
&mut executable_accounts,
|
||||
&mut program_accounts,
|
||||
),
|
||||
Err(InstructionError::AccountBorrowOutstanding)
|
||||
);
|
||||
|
||||
// TODO when the `&mut`s go away test outstanding executable_account refs
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_subset_unchecked_mut() {
|
||||
assert_eq!(
|
||||
get_subset_unchecked_mut(&mut [7, 8], &[0]).unwrap(),
|
||||
vec![&mut 7]
|
||||
);
|
||||
assert_eq!(
|
||||
get_subset_unchecked_mut(&mut [7, 8], &[0, 1]).unwrap(),
|
||||
vec![&mut 7, &mut 8]
|
||||
);
|
||||
}
|
||||
fn test_sum_account_lamports() {
|
||||
let owner_pubkey = Pubkey::new_rand();
|
||||
let account1 = Rc::new(RefCell::new(Account::new(1, 1, &owner_pubkey)));
|
||||
let account2 = Rc::new(RefCell::new(Account::new(2, 1, &owner_pubkey)));
|
||||
let account3 = Rc::new(RefCell::new(Account::new(3, 1, &owner_pubkey)));
|
||||
|
||||
#[test]
|
||||
fn test_get_subset_unchecked_mut_duplicate_index() {
|
||||
// This panics, because it assumes duplicate detection is done elsewhere.
|
||||
assert_eq!(0, MessageProcessor::sum_account_lamports(&mut vec![]));
|
||||
assert_eq!(
|
||||
get_subset_unchecked_mut(&mut [7, 8], &[0, 0]).unwrap_err(),
|
||||
InstructionError::DuplicateAccountIndex
|
||||
6,
|
||||
MessageProcessor::sum_account_lamports(&mut vec![
|
||||
account1.clone(),
|
||||
account2.clone(),
|
||||
account3.clone()
|
||||
])
|
||||
);
|
||||
assert_eq!(
|
||||
3,
|
||||
MessageProcessor::sum_account_lamports(&mut vec![
|
||||
account1.clone(),
|
||||
account2.clone(),
|
||||
account1.clone()
|
||||
])
|
||||
);
|
||||
assert_eq!(
|
||||
1,
|
||||
MessageProcessor::sum_account_lamports(&mut vec![
|
||||
account1.clone(),
|
||||
account1.clone(),
|
||||
account1.clone()
|
||||
])
|
||||
);
|
||||
assert_eq!(
|
||||
6,
|
||||
MessageProcessor::sum_account_lamports(&mut vec![
|
||||
account1.clone(),
|
||||
account2.clone(),
|
||||
account3.clone(),
|
||||
account1.clone(),
|
||||
account2.clone(),
|
||||
account3.clone(),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_get_subset_unchecked_mut_out_of_bounds() {
|
||||
// This panics, because it assumes bounds validation is done elsewhere.
|
||||
get_subset_unchecked_mut(&mut [7, 8], &[2]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -772,13 +812,13 @@ mod tests {
|
|||
match instruction {
|
||||
MockSystemInstruction::Correct => Ok(()),
|
||||
MockSystemInstruction::AttemptCredit { lamports } => {
|
||||
keyed_accounts[0].account.lamports -= lamports;
|
||||
keyed_accounts[1].account.lamports += lamports;
|
||||
keyed_accounts[0].account.borrow_mut().lamports -= lamports;
|
||||
keyed_accounts[1].account.borrow_mut().lamports += lamports;
|
||||
Ok(())
|
||||
}
|
||||
// Change data in a read-only account
|
||||
MockSystemInstruction::AttemptDataChange { data } => {
|
||||
keyed_accounts[1].account.data = vec![data];
|
||||
keyed_accounts[1].account.borrow_mut().data = vec![data];
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -792,14 +832,14 @@ mod tests {
|
|||
message_processor
|
||||
.add_instruction_processor(mock_system_program_id, mock_system_process_instruction);
|
||||
|
||||
let mut accounts: Vec<Account> = Vec::new();
|
||||
let account = Account::new(100, 1, &mock_system_program_id);
|
||||
let mut accounts: Vec<Rc<RefCell<Account>>> = Vec::new();
|
||||
let account = Account::new_ref(100, 1, &mock_system_program_id);
|
||||
accounts.push(account);
|
||||
let account = Account::new(0, 1, &mock_system_program_id);
|
||||
let account = Account::new_ref(0, 1, &mock_system_program_id);
|
||||
accounts.push(account);
|
||||
|
||||
let mut loaders: Vec<Vec<(Pubkey, Account)>> = Vec::new();
|
||||
let account = create_loadable_account("mock_system_program");
|
||||
let mut loaders: Vec<Vec<(Pubkey, RefCell<Account>)>> = Vec::new();
|
||||
let account = RefCell::new(create_loadable_account("mock_system_program"));
|
||||
loaders.push(vec![(mock_system_program_id, account)]);
|
||||
|
||||
let from_pubkey = Pubkey::new_rand();
|
||||
|
@ -816,8 +856,8 @@ mod tests {
|
|||
|
||||
let result = message_processor.process_message(&message, &mut loaders, &mut accounts);
|
||||
assert_eq!(result, Ok(()));
|
||||
assert_eq!(accounts[0].lamports, 100);
|
||||
assert_eq!(accounts[1].lamports, 0);
|
||||
assert_eq!(accounts[0].borrow().lamports, 100);
|
||||
assert_eq!(accounts[1].borrow().lamports, 0);
|
||||
|
||||
let message = Message::new(vec![Instruction::new(
|
||||
mock_system_program_id,
|
||||
|
@ -849,4 +889,124 @@ mod tests {
|
|||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_message_duplicate_accounts() {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum MockSystemInstruction {
|
||||
BorrowFail,
|
||||
MultiBorrowMut,
|
||||
DoWork { lamports: u64, data: u8 },
|
||||
}
|
||||
|
||||
fn mock_system_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
data: &[u8],
|
||||
) -> Result<(), InstructionError> {
|
||||
if let Ok(instruction) = bincode::deserialize(data) {
|
||||
match instruction {
|
||||
MockSystemInstruction::BorrowFail => {
|
||||
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
||||
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
if from_account.lamports != dup_account.lamports {
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
MockSystemInstruction::MultiBorrowMut => {
|
||||
let from_lamports = {
|
||||
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
||||
from_account.lamports
|
||||
};
|
||||
let dup_lamports = {
|
||||
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
dup_account.lamports
|
||||
};
|
||||
if from_lamports != dup_lamports {
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
MockSystemInstruction::DoWork { lamports, data } => {
|
||||
{
|
||||
let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
|
||||
let mut dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
dup_account.lamports -= lamports;
|
||||
to_account.lamports += lamports;
|
||||
dup_account.data = vec![data];
|
||||
}
|
||||
keyed_accounts[0].try_account_ref_mut()?.lamports -= lamports;
|
||||
keyed_accounts[1].try_account_ref_mut()?.lamports += lamports;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(InstructionError::InvalidInstructionData)
|
||||
}
|
||||
}
|
||||
|
||||
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
||||
let mut message_processor = MessageProcessor::default();
|
||||
message_processor
|
||||
.add_instruction_processor(mock_program_id, mock_system_process_instruction);
|
||||
|
||||
let mut accounts: Vec<Rc<RefCell<Account>>> = Vec::new();
|
||||
let account = Account::new_ref(100, 1, &mock_program_id);
|
||||
accounts.push(account);
|
||||
let account = Account::new_ref(0, 1, &mock_program_id);
|
||||
accounts.push(account);
|
||||
|
||||
let mut loaders: Vec<Vec<(Pubkey, RefCell<Account>)>> = Vec::new();
|
||||
let account = RefCell::new(create_loadable_account("mock_system_program"));
|
||||
loaders.push(vec![(mock_program_id, account)]);
|
||||
|
||||
let from_pubkey = Pubkey::new_rand();
|
||||
let to_pubkey = Pubkey::new_rand();
|
||||
let dup_pubkey = from_pubkey.clone();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(from_pubkey, true),
|
||||
AccountMeta::new(to_pubkey, false),
|
||||
AccountMeta::new(dup_pubkey, false),
|
||||
];
|
||||
|
||||
// Try to borrow mut the same account
|
||||
let message = Message::new(vec![Instruction::new(
|
||||
mock_program_id,
|
||||
&MockSystemInstruction::BorrowFail,
|
||||
account_metas.clone(),
|
||||
)]);
|
||||
let result = message_processor.process_message(&message, &mut loaders, &mut accounts);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::AccountBorrowFailed
|
||||
))
|
||||
);
|
||||
|
||||
// Try to borrow mut the same account in a safe way
|
||||
let message = Message::new(vec![Instruction::new(
|
||||
mock_program_id,
|
||||
&MockSystemInstruction::MultiBorrowMut,
|
||||
account_metas.clone(),
|
||||
)]);
|
||||
let result = message_processor.process_message(&message, &mut loaders, &mut accounts);
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
// Do work on the same account but at different location in keyed_accounts[]
|
||||
let message = Message::new(vec![Instruction::new(
|
||||
mock_program_id,
|
||||
&MockSystemInstruction::DoWork {
|
||||
lamports: 10,
|
||||
data: 42,
|
||||
},
|
||||
account_metas,
|
||||
)]);
|
||||
let result = message_processor.process_message(&message, &mut loaders, &mut accounts);
|
||||
assert_eq!(result, Ok(()));
|
||||
assert_eq!(accounts[0].borrow().lamports, 80);
|
||||
assert_eq!(accounts[1].borrow().lamports, 20);
|
||||
assert_eq!(accounts[0].borrow().data, vec![42]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ pub fn invoke_entrypoint(
|
|||
) -> Result<(), InstructionError> {
|
||||
// dispatch it
|
||||
let (names, params) = keyed_accounts.split_at_mut(1);
|
||||
let name_vec = &names[0].account.data;
|
||||
let name_vec = &names[0].try_account_ref()?.data;
|
||||
if let Some(entrypoint) = symbol_cache.read().unwrap().get(name_vec) {
|
||||
unsafe {
|
||||
return entrypoint(program_id, params, instruction_data);
|
||||
|
|
|
@ -196,14 +196,20 @@ mod tests {
|
|||
nonce_account
|
||||
.nonce_initialize(&authorized, &recent_blockhashes, &Rent::free())
|
||||
.unwrap();
|
||||
assert!(verify_nonce(&nonce_account.account, &recent_blockhashes[0]));
|
||||
assert!(verify_nonce(
|
||||
&nonce_account.account.borrow(),
|
||||
&recent_blockhashes[0]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_nonce_bad_acc_state_fail() {
|
||||
with_test_keyed_account(42, true, |nonce_account| {
|
||||
assert!(!verify_nonce(&nonce_account.account, &Hash::default()));
|
||||
assert!(!verify_nonce(
|
||||
&nonce_account.account.borrow(),
|
||||
&Hash::default()
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -221,7 +227,7 @@ mod tests {
|
|||
.nonce_initialize(&authorized, &recent_blockhashes, &Rent::free())
|
||||
.unwrap();
|
||||
assert!(!verify_nonce(
|
||||
&nonce_account.account,
|
||||
&nonce_account.account.borrow(),
|
||||
&recent_blockhashes[1]
|
||||
));
|
||||
});
|
||||
|
|
|
@ -91,7 +91,7 @@ pub(crate) mod tests {
|
|||
storage_instruction::{self, StorageAccountType},
|
||||
storage_processor,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
|
||||
#[test]
|
||||
fn test_store_and_recover() {
|
||||
|
@ -149,25 +149,24 @@ pub(crate) mod tests {
|
|||
let ((validator_pubkey, validator_account), (archiver_pubkey, archiver_account)) =
|
||||
create_storage_accounts_with_credits(credits);
|
||||
|
||||
storage_accounts.store(&validator_pubkey, &validator_account);
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account);
|
||||
storage_accounts.store(&validator_pubkey, &validator_account.borrow());
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account.borrow());
|
||||
// check that 2x credits worth of points are available
|
||||
assert_eq!(storage_accounts.points(), credits * 2);
|
||||
|
||||
let ((validator_pubkey, validator_account), (archiver_pubkey, mut archiver_account)) =
|
||||
let ((validator_pubkey, validator_account), (archiver_pubkey, archiver_account)) =
|
||||
create_storage_accounts_with_credits(credits);
|
||||
|
||||
storage_accounts.store(&validator_pubkey, &validator_account);
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account);
|
||||
storage_accounts.store(&validator_pubkey, &validator_account.borrow());
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account.borrow());
|
||||
// check that 4x credits worth of points are available
|
||||
assert_eq!(storage_accounts.points(), credits * 2 * 2);
|
||||
|
||||
storage_accounts.store(&validator_pubkey, &validator_account);
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account);
|
||||
storage_accounts.store(&validator_pubkey, &validator_account.borrow());
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account.borrow());
|
||||
// check that storing again has no effect
|
||||
assert_eq!(storage_accounts.points(), credits * 2 * 2);
|
||||
|
||||
let storage_contract = &mut archiver_account.state().unwrap();
|
||||
let storage_contract = &mut archiver_account.borrow().state().unwrap();
|
||||
if let StorageContract::ArchiverStorage {
|
||||
credits: account_credits,
|
||||
..
|
||||
|
@ -175,8 +174,11 @@ pub(crate) mod tests {
|
|||
{
|
||||
account_credits.current_epoch += 1;
|
||||
}
|
||||
archiver_account.set_state(storage_contract).unwrap();
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account);
|
||||
archiver_account
|
||||
.borrow_mut()
|
||||
.set_state(storage_contract)
|
||||
.unwrap();
|
||||
storage_accounts.store(&archiver_pubkey, &archiver_account.borrow());
|
||||
|
||||
// check that incremental store increases credits
|
||||
assert_eq!(storage_accounts.points(), credits * 2 * 2 + 1);
|
||||
|
@ -188,48 +190,55 @@ pub(crate) mod tests {
|
|||
|
||||
pub fn create_storage_accounts_with_credits(
|
||||
credits: u64,
|
||||
) -> ((Pubkey, Account), (Pubkey, Account)) {
|
||||
) -> (
|
||||
(Pubkey, Rc<RefCell<Account>>),
|
||||
(Pubkey, Rc<RefCell<Account>>),
|
||||
) {
|
||||
let validator_pubkey = Pubkey::new_rand();
|
||||
let archiver_pubkey = Pubkey::new_rand();
|
||||
|
||||
let mut validator_account = Account::new(
|
||||
let validator_account = Account::new_ref(
|
||||
1,
|
||||
STORAGE_ACCOUNT_SPACE as usize,
|
||||
&solana_storage_program::id(),
|
||||
);
|
||||
let mut validator = StorageAccount::new(validator_pubkey, &mut validator_account);
|
||||
validator
|
||||
.initialize_storage(validator_pubkey, StorageAccountType::Validator)
|
||||
.unwrap();
|
||||
let storage_contract = &mut validator_account.state().unwrap();
|
||||
if let StorageContract::ValidatorStorage {
|
||||
credits: account_credits,
|
||||
..
|
||||
} = storage_contract
|
||||
{
|
||||
account_credits.current_epoch = credits;
|
||||
}
|
||||
validator_account.set_state(storage_contract).unwrap();
|
||||
|
||||
let mut archiver_account = Account::new(
|
||||
let archiver_account = Account::new_ref(
|
||||
1,
|
||||
STORAGE_ACCOUNT_SPACE as usize,
|
||||
&solana_storage_program::id(),
|
||||
);
|
||||
let mut archiver = StorageAccount::new(archiver_pubkey, &mut archiver_account);
|
||||
archiver
|
||||
.initialize_storage(archiver_pubkey, StorageAccountType::Archiver)
|
||||
.unwrap();
|
||||
let storage_contract = &mut archiver_account.state().unwrap();
|
||||
if let StorageContract::ArchiverStorage {
|
||||
credits: account_credits,
|
||||
..
|
||||
} = storage_contract
|
||||
{
|
||||
account_credits.current_epoch = credits;
|
||||
}
|
||||
archiver_account.set_state(storage_contract).unwrap();
|
||||
StorageAccount::new(validator_pubkey, &mut validator_account.borrow_mut())
|
||||
.initialize_storage(validator_pubkey, StorageAccountType::Validator)
|
||||
.unwrap();
|
||||
let storage_contract = &mut validator_account.borrow().state().unwrap();
|
||||
if let StorageContract::ValidatorStorage {
|
||||
credits: account_credits,
|
||||
..
|
||||
} = storage_contract
|
||||
{
|
||||
account_credits.current_epoch = credits;
|
||||
}
|
||||
validator_account
|
||||
.borrow_mut()
|
||||
.set_state(storage_contract)
|
||||
.unwrap();
|
||||
|
||||
StorageAccount::new(archiver_pubkey, &mut archiver_account.borrow_mut())
|
||||
.initialize_storage(archiver_pubkey, StorageAccountType::Archiver)
|
||||
.unwrap();
|
||||
let storage_contract = &mut archiver_account.borrow().state().unwrap();
|
||||
if let StorageContract::ArchiverStorage {
|
||||
credits: account_credits,
|
||||
..
|
||||
} = storage_contract
|
||||
{
|
||||
account_credits.current_epoch = credits;
|
||||
}
|
||||
archiver_account
|
||||
.borrow_mut()
|
||||
.set_state(storage_contract)
|
||||
.unwrap();
|
||||
}
|
||||
(
|
||||
(validator_pubkey, validator_account),
|
||||
(archiver_pubkey, archiver_account),
|
||||
|
|
|
@ -151,20 +151,20 @@ fn transfer(
|
|||
return Err(InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
if !from.account.data.is_empty() {
|
||||
if !from.data_is_empty()? {
|
||||
debug!("Transfer: `from` must not carry data");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
|
||||
if lamports > from.account.lamports {
|
||||
if lamports > from.lamports()? {
|
||||
debug!(
|
||||
"Transfer: insufficient lamports ({}, need {})",
|
||||
from.account.lamports, lamports
|
||||
from.lamports()?,
|
||||
lamports
|
||||
);
|
||||
return Err(SystemError::ResultWithNegativeLamports.into());
|
||||
}
|
||||
|
||||
from.account.lamports -= lamports;
|
||||
from.try_account_ref_mut()?.lamports -= lamports;
|
||||
to.lamports += lamports;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -190,10 +190,11 @@ pub fn process_instruction(
|
|||
} => {
|
||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut to_account = to.try_account_ref_mut()?;
|
||||
let to_address = Address::create(to.unsigned_key(), None)?;
|
||||
create_account(
|
||||
from,
|
||||
to.account,
|
||||
&mut to_account,
|
||||
&to_address,
|
||||
lamports,
|
||||
space,
|
||||
|
@ -210,12 +211,12 @@ pub fn process_instruction(
|
|||
} => {
|
||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut to_account = to.try_account_ref_mut()?;
|
||||
let to_address =
|
||||
Address::create(&to.unsigned_key(), Some((&base, &seed, &program_id)))?;
|
||||
|
||||
create_account(
|
||||
from,
|
||||
to.account,
|
||||
&mut to_account,
|
||||
&to_address,
|
||||
lamports,
|
||||
space,
|
||||
|
@ -225,13 +226,14 @@ pub fn process_instruction(
|
|||
}
|
||||
SystemInstruction::Assign { program_id } => {
|
||||
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut account = keyed_account.try_account_ref_mut()?;
|
||||
let address = Address::create(keyed_account.unsigned_key(), None)?;
|
||||
assign(keyed_account.account, &address, &program_id, &signers)
|
||||
assign(&mut account, &address, &program_id, &signers)
|
||||
}
|
||||
SystemInstruction::Transfer { lamports } => {
|
||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||
transfer(from, to.account, lamports)
|
||||
let mut to_account = next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?;
|
||||
transfer(from, &mut to_account, lamports)
|
||||
}
|
||||
SystemInstruction::AdvanceNonceAccount => {
|
||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
|
@ -265,9 +267,9 @@ pub fn process_instruction(
|
|||
}
|
||||
SystemInstruction::Allocate { space } => {
|
||||
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut account = keyed_account.try_account_ref_mut()?;
|
||||
let address = Address::create(keyed_account.unsigned_key(), None)?;
|
||||
|
||||
allocate(keyed_account.account, &address, space, &signers)
|
||||
allocate(&mut account, &address, space, &signers)
|
||||
}
|
||||
SystemInstruction::AllocateWithSeed {
|
||||
base,
|
||||
|
@ -276,17 +278,12 @@ pub fn process_instruction(
|
|||
program_id,
|
||||
} => {
|
||||
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut account = keyed_account.try_account_ref_mut()?;
|
||||
let address = Address::create(
|
||||
keyed_account.unsigned_key(),
|
||||
Some((&base, &seed, &program_id)),
|
||||
)?;
|
||||
allocate_and_assign(
|
||||
keyed_account.account,
|
||||
&address,
|
||||
space,
|
||||
&program_id,
|
||||
&signers,
|
||||
)
|
||||
allocate_and_assign(&mut account, &address, space, &program_id, &signers)
|
||||
}
|
||||
SystemInstruction::AssignWithSeed {
|
||||
base,
|
||||
|
@ -294,12 +291,13 @@ pub fn process_instruction(
|
|||
program_id,
|
||||
} => {
|
||||
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||
let mut account = keyed_account.try_account_ref_mut()?;
|
||||
let address = Address::create(
|
||||
keyed_account.unsigned_key(),
|
||||
Some((&base, &seed, &program_id)),
|
||||
)?;
|
||||
|
||||
assign(keyed_account.account, &address, &program_id, &signers)
|
||||
assign(&mut account, &address, &program_id, &signers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,6 +339,7 @@ mod tests {
|
|||
system_instruction, system_program, sysvar,
|
||||
transaction::TransactionError,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
impl From<Pubkey> for Address {
|
||||
fn from(address: Pubkey) -> Self {
|
||||
|
@ -351,13 +350,29 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_default_account() -> RefCell<Account> {
|
||||
RefCell::new(Account::default())
|
||||
}
|
||||
fn create_default_recent_blockhashes_account() -> RefCell<Account> {
|
||||
RefCell::new(sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
))
|
||||
}
|
||||
fn create_default_rent_account() -> RefCell<Account> {
|
||||
RefCell::new(sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_account() {
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let to = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
let mut to_account = Account::new_ref(0, 0, &Pubkey::default());
|
||||
|
||||
assert_eq!(
|
||||
process_instruction(
|
||||
|
@ -375,10 +390,10 @@ mod tests {
|
|||
),
|
||||
Ok(())
|
||||
);
|
||||
assert_eq!(from_account.lamports, 50);
|
||||
assert_eq!(to_account.lamports, 50);
|
||||
assert_eq!(to_account.owner, new_program_owner);
|
||||
assert_eq!(to_account.data, [0, 0]);
|
||||
assert_eq!(from_account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.borrow().owner, new_program_owner);
|
||||
assert_eq!(to_account.borrow().data, [0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -388,8 +403,8 @@ mod tests {
|
|||
let seed = "shiny pepper";
|
||||
let to = create_address_with_seed(&from, seed, &new_program_owner).unwrap();
|
||||
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
let mut to_account = Account::new_ref(0, 0, &Pubkey::default());
|
||||
|
||||
assert_eq!(
|
||||
process_instruction(
|
||||
|
@ -409,10 +424,10 @@ mod tests {
|
|||
),
|
||||
Ok(())
|
||||
);
|
||||
assert_eq!(from_account.lamports, 50);
|
||||
assert_eq!(to_account.lamports, 50);
|
||||
assert_eq!(to_account.owner, new_program_owner);
|
||||
assert_eq!(to_account.data, [0, 0]);
|
||||
assert_eq!(from_account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.borrow().owner, new_program_owner);
|
||||
assert_eq!(to_account.borrow().data, [0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -435,13 +450,13 @@ mod tests {
|
|||
let seed = "dull boy";
|
||||
let to = create_address_with_seed(&from, seed, &new_program_owner).unwrap();
|
||||
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||
let to_address = Address::create(&to, Some((&from, seed, &new_program_owner))).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
create_account(
|
||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||
&mut KeyedAccount::new(&from, false, &from_account),
|
||||
&mut to_account,
|
||||
&to_address,
|
||||
50,
|
||||
|
@ -451,7 +466,7 @@ mod tests {
|
|||
),
|
||||
Err(InstructionError::MissingRequiredSignature)
|
||||
);
|
||||
assert_eq!(from_account.lamports, 100);
|
||||
assert_eq!(from_account.borrow().lamports, 100);
|
||||
assert_eq!(to_account, Account::default());
|
||||
}
|
||||
|
||||
|
@ -460,14 +475,14 @@ mod tests {
|
|||
// create account with zero lamports tranferred
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 1, &Pubkey::new_rand()); // not from system account
|
||||
let from_account = Account::new_ref(100, 1, &Pubkey::new_rand()); // not from system account
|
||||
|
||||
let to = Pubkey::new_rand();
|
||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||
|
||||
assert_eq!(
|
||||
create_account(
|
||||
&mut KeyedAccount::new(&from, false, &mut from_account), // no signer
|
||||
&mut KeyedAccount::new(&from, false, &from_account), // no signer
|
||||
&mut to_account,
|
||||
&to.into(),
|
||||
0,
|
||||
|
@ -478,7 +493,7 @@ mod tests {
|
|||
Ok(())
|
||||
);
|
||||
|
||||
let from_lamports = from_account.lamports;
|
||||
let from_lamports = from_account.borrow().lamports;
|
||||
let to_lamports = to_account.lamports;
|
||||
let to_owner = to_account.owner;
|
||||
let to_data = to_account.data.clone();
|
||||
|
@ -493,7 +508,7 @@ mod tests {
|
|||
// Attempt to create account with more lamports than remaining in from_account
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
|
||||
let to = Pubkey::new_rand();
|
||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||
|
@ -512,7 +527,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_request_more_than_allowed_data_length() {
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
let from = Pubkey::new_rand();
|
||||
let mut to_account = Account::default();
|
||||
let to = Pubkey::new_rand();
|
||||
|
@ -556,7 +571,7 @@ mod tests {
|
|||
// Attempt to create system account in account already owned by another program
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
|
||||
let original_program_owner = Pubkey::new(&[5; 32]);
|
||||
let owned_key = Pubkey::new_rand();
|
||||
|
@ -567,7 +582,7 @@ mod tests {
|
|||
let owned_address = owned_key.into();
|
||||
|
||||
let result = create_account(
|
||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||
&mut KeyedAccount::new(&from, true, &from_account),
|
||||
&mut owned_account,
|
||||
&owned_address,
|
||||
50,
|
||||
|
@ -577,7 +592,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
||||
|
||||
let from_lamports = from_account.lamports;
|
||||
let from_lamports = from_account.borrow().lamports;
|
||||
assert_eq!(from_lamports, 100);
|
||||
assert_eq!(owned_account, unchanged_account);
|
||||
|
||||
|
@ -585,7 +600,7 @@ mod tests {
|
|||
let mut owned_account = Account::new(0, 1, &Pubkey::default());
|
||||
let unchanged_account = owned_account.clone();
|
||||
let result = create_account(
|
||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||
&mut KeyedAccount::new(&from, true, &from_account),
|
||||
&mut owned_account,
|
||||
&owned_address,
|
||||
50,
|
||||
|
@ -594,14 +609,14 @@ mod tests {
|
|||
&signers,
|
||||
);
|
||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
||||
let from_lamports = from_account.lamports;
|
||||
let from_lamports = from_account.borrow().lamports;
|
||||
assert_eq!(from_lamports, 100);
|
||||
assert_eq!(owned_account, unchanged_account);
|
||||
|
||||
// Verify that create_account works even if `to` has a non-zero balance
|
||||
let mut owned_account = Account::new(1, 0, &Pubkey::default());
|
||||
let result = create_account(
|
||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||
&mut KeyedAccount::new(&from, true, &from_account),
|
||||
&mut owned_account,
|
||||
&owned_address,
|
||||
50,
|
||||
|
@ -610,7 +625,7 @@ mod tests {
|
|||
&signers,
|
||||
);
|
||||
assert_eq!(result, Ok(()));
|
||||
assert_eq!(from_account.lamports, from_lamports - 50);
|
||||
assert_eq!(from_account.borrow().lamports, from_lamports - 50);
|
||||
assert_eq!(owned_account.lamports, 1 + 50);
|
||||
}
|
||||
|
||||
|
@ -619,7 +634,7 @@ mod tests {
|
|||
// Attempt to create an account without signing the transfer
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
|
||||
let owned_key = Pubkey::new_rand();
|
||||
let mut owned_account = Account::new(0, 0, &Pubkey::default());
|
||||
|
@ -669,7 +684,7 @@ mod tests {
|
|||
fn test_create_sysvar_invalid_id() {
|
||||
// Attempt to create system account in account already owned by another program
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
|
||||
let to = Pubkey::new_rand();
|
||||
let mut to_account = Account::default();
|
||||
|
@ -696,7 +711,7 @@ mod tests {
|
|||
// Attempt to create system account in account with populated data
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
|
||||
let populated_key = Pubkey::new_rand();
|
||||
let mut populated_account = Account {
|
||||
|
@ -725,7 +740,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_create_from_account_is_nonce_fail() {
|
||||
let nonce = Pubkey::new_rand();
|
||||
let mut nonce_account = Account::new_data(
|
||||
let mut nonce_account = Account::new_ref_data(
|
||||
42,
|
||||
&nonce_state::NonceState::Initialized(
|
||||
nonce_state::Meta::new(&Pubkey::default()),
|
||||
|
@ -783,6 +798,7 @@ mod tests {
|
|||
Ok(())
|
||||
);
|
||||
|
||||
let mut account = RefCell::new(account);
|
||||
assert_eq!(
|
||||
process_instruction(
|
||||
&Pubkey::default(),
|
||||
|
@ -825,7 +841,7 @@ mod tests {
|
|||
assert_eq!(result, Err(InstructionError::NotEnoughAccountKeys));
|
||||
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||
let mut from_account = Account::new_ref(100, 0, &system_program::id());
|
||||
// Attempt to transfer with no destination
|
||||
let instruction = SystemInstruction::Transfer { lamports: 0 };
|
||||
let data = serialize(&instruction).unwrap();
|
||||
|
@ -840,51 +856,40 @@ mod tests {
|
|||
#[test]
|
||||
fn test_transfer_lamports() {
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter
|
||||
let from_account = Account::new_ref(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter
|
||||
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
|
||||
transfer(
|
||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||
&mut to_account,
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
let from_lamports = from_account.lamports;
|
||||
let mut from_keyed_account = KeyedAccount::new(&from, true, &from_account);
|
||||
transfer(&mut from_keyed_account, &mut to_account, 50).unwrap();
|
||||
let from_lamports = from_keyed_account.account.borrow().lamports;
|
||||
let to_lamports = to_account.lamports;
|
||||
assert_eq!(from_lamports, 50);
|
||||
assert_eq!(to_lamports, 51);
|
||||
|
||||
// Attempt to move more lamports than remaining in from_account
|
||||
let result = transfer(
|
||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||
&mut to_account,
|
||||
100,
|
||||
);
|
||||
let mut from_keyed_account = KeyedAccount::new(&from, true, &from_account);
|
||||
let result = transfer(&mut from_keyed_account, &mut to_account, 100);
|
||||
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
|
||||
assert_eq!(from_account.lamports, 50);
|
||||
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.lamports, 51);
|
||||
|
||||
// test unsigned transfer of zero
|
||||
assert!(transfer(
|
||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||
&mut to_account,
|
||||
0,
|
||||
)
|
||||
.is_ok(),);
|
||||
assert_eq!(from_account.lamports, 50);
|
||||
let mut from_keyed_account = KeyedAccount::new(&from, false, &from_account);
|
||||
assert!(transfer(&mut from_keyed_account, &mut to_account, 0,).is_ok(),);
|
||||
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
|
||||
assert_eq!(to_account.lamports, 51);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transfer_lamports_from_nonce_account_fail() {
|
||||
let from = Pubkey::new_rand();
|
||||
let mut from_account = Account::new_data(
|
||||
let mut from_account = Account::new_ref_data(
|
||||
100,
|
||||
&nonce_state::NonceState::Initialized(nonce_state::Meta::new(&from), Hash::default()),
|
||||
&system_program::id(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
get_system_account_kind(&from_account),
|
||||
get_system_account_kind(&from_account.borrow()),
|
||||
Some(SystemAccountKind::Nonce)
|
||||
);
|
||||
|
||||
|
@ -1009,7 +1014,7 @@ mod tests {
|
|||
.accounts
|
||||
.iter()
|
||||
.map(|meta| {
|
||||
if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
|
||||
RefCell::new(if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
|
||||
sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
|
@ -1018,7 +1023,7 @@ mod tests {
|
|||
sysvar::rent::create_account(1, &Rent::free())
|
||||
} else {
|
||||
Account::default()
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1068,7 +1073,7 @@ mod tests {
|
|||
&mut [KeyedAccount::new(
|
||||
&Pubkey::default(),
|
||||
true,
|
||||
&mut Account::default(),
|
||||
&create_default_account(),
|
||||
),],
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
),
|
||||
|
@ -1082,11 +1087,11 @@ mod tests {
|
|||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default(),),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut Account::default(),
|
||||
&create_default_account(),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
|
@ -1105,20 +1110,18 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::free()),
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_rent_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let new_recent_blockhashes_account =
|
||||
RefCell::new(sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &hash(&serialize(&0).unwrap())); 32].into_iter(),
|
||||
));
|
||||
assert_eq!(
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
|
@ -1127,10 +1130,7 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &hash(&serialize(&0).unwrap())); 32].into_iter(),
|
||||
),
|
||||
&new_recent_blockhashes_account,
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
|
@ -1172,7 +1172,7 @@ mod tests {
|
|||
&mut [KeyedAccount::new(
|
||||
&Pubkey::default(),
|
||||
true,
|
||||
&mut Account::default(),
|
||||
&create_default_account()
|
||||
),],
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
|
@ -1186,12 +1186,12 @@ 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, &create_default_account()),
|
||||
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut Account::default(),
|
||||
&create_default_account()
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
|
@ -1211,16 +1211,13 @@ mod tests {
|
|||
true,
|
||||
&mut nonce_state::create_account(1_000_000),
|
||||
),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default(),),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
|
@ -1239,20 +1236,13 @@ mod tests {
|
|||
true,
|
||||
&mut nonce_state::create_account(1_000_000),
|
||||
),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default(),),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut create_default_account()),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::free())
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_rent_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
|
@ -1302,7 +1292,7 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut Account::default(),
|
||||
&create_default_account()
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
|
@ -1325,12 +1315,9 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
|
@ -1352,16 +1339,9 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::free())
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_rent_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
|
@ -1379,16 +1359,9 @@ mod tests {
|
|||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::free()),
|
||||
&create_default_recent_blockhashes_account(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_rent_account()),
|
||||
],
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
)
|
||||
|
@ -1444,7 +1417,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_get_system_account_kind_uninitialized_nonce_account_fail() {
|
||||
assert_eq!(
|
||||
get_system_account_kind(&nonce_state::create_account(42)),
|
||||
get_system_account_kind(&nonce_state::create_account(42).borrow()),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use crate::hash::Hash;
|
||||
use crate::instruction::InstructionError;
|
||||
use crate::{clock::Epoch, pubkey::Pubkey};
|
||||
use std::{cmp, fmt, iter::FromIterator};
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
cmp, fmt,
|
||||
iter::FromIterator,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
/// An Account with data that is stored on chain
|
||||
#[repr(C)]
|
||||
|
@ -69,6 +75,9 @@ impl Account {
|
|||
..Self::default()
|
||||
}
|
||||
}
|
||||
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
|
||||
Rc::new(RefCell::new(Self::new(lamports, space, owner)))
|
||||
}
|
||||
|
||||
pub fn new_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
|
@ -83,6 +92,13 @@ impl Account {
|
|||
..Self::default()
|
||||
})
|
||||
}
|
||||
pub fn new_ref_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
Ok(RefCell::new(Self::new_data(lamports, state, owner)?))
|
||||
}
|
||||
|
||||
pub fn new_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
|
@ -96,6 +112,16 @@ impl Account {
|
|||
|
||||
Ok(account)
|
||||
}
|
||||
pub fn new_ref_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
Ok(RefCell::new(Self::new_data_with_space(
|
||||
lamports, state, space, owner,
|
||||
)?))
|
||||
}
|
||||
|
||||
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
|
||||
bincode::deserialize(&self.data)
|
||||
|
@ -115,7 +141,7 @@ pub struct KeyedAccount<'a> {
|
|||
is_signer: bool, // Transaction was signed by this account's key
|
||||
is_writable: bool,
|
||||
key: &'a Pubkey,
|
||||
pub account: &'a mut Account,
|
||||
pub account: &'a RefCell<Account>,
|
||||
}
|
||||
|
||||
impl<'a> KeyedAccount<'a> {
|
||||
|
@ -135,7 +161,46 @@ impl<'a> KeyedAccount<'a> {
|
|||
self.is_writable
|
||||
}
|
||||
|
||||
pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a mut Account) -> Self {
|
||||
pub fn lamports(&self) -> Result<u64, InstructionError> {
|
||||
Ok(self.try_borrow()?.lamports)
|
||||
}
|
||||
|
||||
pub fn data_len(&self) -> Result<usize, InstructionError> {
|
||||
Ok(self.try_borrow()?.data.len())
|
||||
}
|
||||
|
||||
pub fn data_is_empty(&self) -> Result<bool, InstructionError> {
|
||||
Ok(self.try_borrow()?.data.is_empty())
|
||||
}
|
||||
|
||||
pub fn owner(&self) -> Result<Pubkey, InstructionError> {
|
||||
Ok(self.try_borrow()?.owner)
|
||||
}
|
||||
|
||||
pub fn executable(&self) -> Result<bool, InstructionError> {
|
||||
Ok(self.try_borrow()?.executable)
|
||||
}
|
||||
|
||||
pub fn try_account_ref(&'a self) -> Result<Ref<Account>, InstructionError> {
|
||||
self.try_borrow()
|
||||
}
|
||||
|
||||
pub fn try_account_ref_mut(&'a self) -> Result<RefMut<Account>, InstructionError> {
|
||||
self.try_borrow_mut()
|
||||
}
|
||||
|
||||
fn try_borrow(&self) -> Result<Ref<Account>, InstructionError> {
|
||||
self.account
|
||||
.try_borrow()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)
|
||||
}
|
||||
fn try_borrow_mut(&self) -> Result<RefMut<Account>, InstructionError> {
|
||||
self.account
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)
|
||||
}
|
||||
|
||||
pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: true,
|
||||
|
@ -144,7 +209,7 @@ impl<'a> KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a mut Account) -> Self {
|
||||
pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: false,
|
||||
|
@ -154,8 +219,14 @@ impl<'a> KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(&'a Pubkey, &'a mut Account)> for KeyedAccount<'a> {
|
||||
fn from((key, account): (&'a Pubkey, &'a mut Account)) -> Self {
|
||||
impl<'a> PartialEq for KeyedAccount<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.key == other.key
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): (&'a Pubkey, &'a RefCell<Account>)) -> Self {
|
||||
Self {
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
|
@ -165,8 +236,8 @@ impl<'a> From<(&'a Pubkey, &'a mut Account)> for KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(&'a Pubkey, bool, &'a mut Account)> for KeyedAccount<'a> {
|
||||
fn from((key, is_signer, account): (&'a Pubkey, bool, &'a mut Account)) -> Self {
|
||||
impl<'a> From<(&'a Pubkey, bool, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, is_signer, account): (&'a Pubkey, bool, &'a RefCell<Account>)) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: true,
|
||||
|
@ -176,8 +247,8 @@ impl<'a> From<(&'a Pubkey, bool, &'a mut Account)> for KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut (Pubkey, Account)> for KeyedAccount<'a> {
|
||||
fn from((key, account): &'a mut (Pubkey, Account)) -> Self {
|
||||
impl<'a> From<&'a mut (&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): &'a mut (&'a Pubkey, &'a RefCell<Account>)) -> Self {
|
||||
Self {
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
|
@ -187,12 +258,14 @@ impl<'a> From<&'a mut (Pubkey, Account)> for KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_keyed_accounts(accounts: &mut [(Pubkey, Account)]) -> Vec<KeyedAccount> {
|
||||
pub fn create_keyed_accounts<'a>(
|
||||
accounts: &'a mut [(&'a Pubkey, &'a RefCell<Account>)],
|
||||
) -> Vec<KeyedAccount<'a>> {
|
||||
accounts.iter_mut().map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn create_keyed_is_signer_accounts<'a>(
|
||||
accounts: &'a mut [(&'a Pubkey, bool, &'a mut Account)],
|
||||
accounts: &'a mut [(&'a Pubkey, bool, &'a mut RefCell<Account>)],
|
||||
) -> Vec<KeyedAccount<'a>> {
|
||||
accounts
|
||||
.iter_mut()
|
||||
|
@ -205,7 +278,9 @@ pub fn create_keyed_is_signer_accounts<'a>(
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_keyed_readonly_accounts(accounts: &mut [(Pubkey, Account)]) -> Vec<KeyedAccount> {
|
||||
pub fn create_keyed_readonly_accounts(
|
||||
accounts: &mut [(Pubkey, RefCell<Account>)],
|
||||
) -> Vec<KeyedAccount> {
|
||||
accounts
|
||||
.iter_mut()
|
||||
.map(|(key, account)| KeyedAccount {
|
||||
|
|
|
@ -30,10 +30,10 @@ where
|
|||
T: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn state(&self) -> Result<T, InstructionError> {
|
||||
self.account.state()
|
||||
self.try_account_ref()?.state()
|
||||
}
|
||||
fn set_state(&mut self, state: &T) -> Result<(), InstructionError> {
|
||||
self.account.set_state(state)
|
||||
self.try_account_ref_mut()?.set_state(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ pub enum InstructionError {
|
|||
ReadonlyDataModified,
|
||||
|
||||
/// An account was referenced more than once in a single instruction
|
||||
// Deprecated, instructions can now contain duplicate accounts
|
||||
DuplicateAccountIndex,
|
||||
|
||||
/// Executable bit on account changed, but shouldn't have
|
||||
|
@ -76,6 +77,17 @@ pub enum InstructionError {
|
|||
/// The instruction expected an executable account
|
||||
AccountNotExecutable,
|
||||
|
||||
/// Failed to borrow a reference to an account, already borrowed
|
||||
AccountBorrowFailed,
|
||||
|
||||
/// Account has an outstanding reference after a program's execution
|
||||
AccountBorrowOutstanding,
|
||||
|
||||
/// The same account was multiply passed to an on-chain program's entrypoint, but the program
|
||||
/// modified them differently. A program can only modify one instance of the account because
|
||||
/// the runtime cannot determine which changes to pick or how to merge them if both are modified
|
||||
DuplicateAccountOutOfSync,
|
||||
|
||||
/// CustomError allows on-chain programs to implement program-specific error types and see
|
||||
/// them returned by the Solana runtime. A CustomError may be any type that is represented
|
||||
/// as or serialized to a u32 integer.
|
||||
|
|
|
@ -115,8 +115,8 @@ pub fn next_keyed_account<I: Iterator>(iter: &mut I) -> Result<I::Item, Instruct
|
|||
|
||||
/// Return true if the first keyed_account is executable, used to determine if
|
||||
/// the loader should call a program's 'main'
|
||||
pub fn is_executable(keyed_accounts: &[KeyedAccount]) -> bool {
|
||||
!keyed_accounts.is_empty() && keyed_accounts[0].account.executable
|
||||
pub fn is_executable(keyed_accounts: &[KeyedAccount]) -> Result<bool, InstructionError> {
|
||||
Ok(!keyed_accounts.is_empty() && keyed_accounts[0].executable()?)
|
||||
}
|
||||
|
||||
pub fn limited_deserialize<T>(instruction_data: &[u8]) -> Result<T, InstructionError>
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
sysvar::rent::Rent,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::{cell::RefCell, collections::HashSet};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
||||
pub struct Meta {
|
||||
|
@ -107,19 +107,19 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
) -> Result<(), InstructionError> {
|
||||
let signer = match self.state()? {
|
||||
NonceState::Uninitialized => {
|
||||
if lamports > self.account.lamports {
|
||||
if lamports > self.lamports()? {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
*self.unsigned_key()
|
||||
}
|
||||
NonceState::Initialized(meta, ref hash) => {
|
||||
if lamports == self.account.lamports {
|
||||
if lamports == self.lamports()? {
|
||||
if *hash == recent_blockhashes[0] {
|
||||
return Err(NonceError::NotExpired.into());
|
||||
}
|
||||
} else {
|
||||
let min_balance = rent.minimum_balance(self.account.data.len());
|
||||
if lamports + min_balance > self.account.lamports {
|
||||
let min_balance = rent.minimum_balance(self.data_len()?);
|
||||
if lamports + min_balance > self.lamports()? {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
return Err(InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
self.account.lamports -= lamports;
|
||||
to.account.lamports += lamports;
|
||||
self.try_account_ref_mut()?.lamports -= lamports;
|
||||
to.try_account_ref_mut()?.lamports += lamports;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -149,8 +149,8 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
|
||||
let meta = match self.state()? {
|
||||
NonceState::Uninitialized => {
|
||||
let min_balance = rent.minimum_balance(self.account.data.len());
|
||||
if self.account.lamports < min_balance {
|
||||
let min_balance = rent.minimum_balance(self.data_len()?);
|
||||
if self.lamports()? < min_balance {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
Meta::new(nonce_authority)
|
||||
|
@ -178,14 +178,16 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_account(lamports: u64) -> Account {
|
||||
Account::new_data_with_space(
|
||||
lamports,
|
||||
&NonceState::Uninitialized,
|
||||
NonceState::size(),
|
||||
&system_program::id(),
|
||||
pub fn create_account(lamports: u64) -> RefCell<Account> {
|
||||
RefCell::new(
|
||||
Account::new_data_with_space(
|
||||
lamports,
|
||||
&NonceState::Uninitialized,
|
||||
NonceState::size(),
|
||||
&system_program::id(),
|
||||
)
|
||||
.expect("nonce_account"),
|
||||
)
|
||||
.expect("nonce_account")
|
||||
}
|
||||
|
||||
/// Convenience function for working with keyed accounts in tests
|
||||
|
@ -195,8 +197,8 @@ where
|
|||
F: FnMut(&mut KeyedAccount),
|
||||
{
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let mut account = create_account(lamports);
|
||||
let mut keyed_account = KeyedAccount::new(&pubkey, signer, &mut account);
|
||||
let account = create_account(lamports);
|
||||
let mut keyed_account = KeyedAccount::new(&pubkey, signer, &account);
|
||||
f(&mut keyed_account)
|
||||
}
|
||||
|
||||
|
@ -262,9 +264,10 @@ mod test {
|
|||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let withdraw_lamports = keyed_account.account.lamports;
|
||||
let expect_nonce_lamports = keyed_account.account.lamports - withdraw_lamports;
|
||||
let expect_to_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
let withdraw_lamports = keyed_account.account.borrow().lamports;
|
||||
let expect_nonce_lamports =
|
||||
keyed_account.account.borrow().lamports - withdraw_lamports;
|
||||
let expect_to_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
keyed_account
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -275,9 +278,12 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
// Empties NonceAccount balance
|
||||
assert_eq!(keyed_account.account.lamports, expect_nonce_lamports);
|
||||
assert_eq!(
|
||||
keyed_account.account.borrow().lamports,
|
||||
expect_nonce_lamports
|
||||
);
|
||||
// NonceAccount balance goes to `to`
|
||||
assert_eq!(to_keyed.account.lamports, expect_to_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, expect_to_lamports);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -297,7 +303,7 @@ mod test {
|
|||
nonce_account
|
||||
.nonce_initialize(&authorized, &recent_blockhashes, &rent)
|
||||
.unwrap();
|
||||
let pubkey = nonce_account.account.owner.clone();
|
||||
let pubkey = nonce_account.account.borrow().owner.clone();
|
||||
let mut nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account);
|
||||
let state: NonceState = nonce_account.state().unwrap();
|
||||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
|
@ -426,9 +432,10 @@ mod test {
|
|||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let withdraw_lamports = nonce_keyed.account.lamports;
|
||||
let expect_nonce_lamports = nonce_keyed.account.lamports - withdraw_lamports;
|
||||
let expect_to_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports;
|
||||
let expect_nonce_lamports =
|
||||
nonce_keyed.account.borrow().lamports - withdraw_lamports;
|
||||
let expect_to_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
nonce_keyed
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -443,9 +450,9 @@ mod test {
|
|||
// Deinitializes NonceAccount state
|
||||
assert_eq!(state, NonceState::Uninitialized);
|
||||
// Empties NonceAccount balance
|
||||
assert_eq!(nonce_keyed.account.lamports, expect_nonce_lamports);
|
||||
assert_eq!(nonce_keyed.account.borrow().lamports, expect_nonce_lamports);
|
||||
// NonceAccount balance goes to `to`
|
||||
assert_eq!(to_keyed.account.lamports, expect_to_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, expect_to_lamports);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -463,8 +470,9 @@ mod test {
|
|||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let signers = HashSet::new();
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let lamports = nonce_keyed.account.borrow().lamports;
|
||||
let result = nonce_keyed.nonce_withdraw(
|
||||
nonce_keyed.account.lamports,
|
||||
lamports,
|
||||
&mut to_keyed,
|
||||
&recent_blockhashes,
|
||||
&rent,
|
||||
|
@ -489,8 +497,9 @@ mod test {
|
|||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let lamports = nonce_keyed.account.borrow().lamports + 1;
|
||||
let result = nonce_keyed.nonce_withdraw(
|
||||
nonce_keyed.account.lamports + 1,
|
||||
lamports,
|
||||
&mut to_keyed,
|
||||
&recent_blockhashes,
|
||||
&rent,
|
||||
|
@ -513,9 +522,10 @@ mod test {
|
|||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let withdraw_lamports = nonce_keyed.account.lamports / 2;
|
||||
let nonce_expect_lamports = nonce_keyed.account.lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports / 2;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
nonce_keyed
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -527,11 +537,12 @@ mod test {
|
|||
.unwrap();
|
||||
let state: NonceState = nonce_keyed.state().unwrap();
|
||||
assert_eq!(state, NonceState::Uninitialized);
|
||||
assert_eq!(nonce_keyed.account.lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.lamports, to_expect_lamports);
|
||||
let withdraw_lamports = nonce_keyed.account.lamports;
|
||||
let nonce_expect_lamports = nonce_keyed.account.lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
nonce_keyed
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -543,8 +554,8 @@ mod test {
|
|||
.unwrap();
|
||||
let state: NonceState = nonce_keyed.state().unwrap();
|
||||
assert_eq!(state, NonceState::Uninitialized);
|
||||
assert_eq!(nonce_keyed.account.lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.lamports, to_expect_lamports);
|
||||
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -569,9 +580,10 @@ mod test {
|
|||
let stored = recent_blockhashes[0];
|
||||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let withdraw_lamports = nonce_keyed.account.lamports - min_lamports;
|
||||
let nonce_expect_lamports = nonce_keyed.account.lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports - min_lamports;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
nonce_keyed
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -584,12 +596,13 @@ mod test {
|
|||
let state: NonceState = nonce_keyed.state().unwrap();
|
||||
let stored = recent_blockhashes[0];
|
||||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
assert_eq!(nonce_keyed.account.lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.lamports, to_expect_lamports);
|
||||
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let withdraw_lamports = nonce_keyed.account.lamports;
|
||||
let nonce_expect_lamports = nonce_keyed.account.lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.lamports + withdraw_lamports;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports - withdraw_lamports;
|
||||
let to_expect_lamports = to_keyed.account.borrow().lamports + withdraw_lamports;
|
||||
nonce_keyed
|
||||
.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
|
@ -599,8 +612,8 @@ mod test {
|
|||
&signers,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(nonce_keyed.account.lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.lamports, to_expect_lamports);
|
||||
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
||||
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -621,7 +634,7 @@ mod test {
|
|||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let withdraw_lamports = nonce_keyed.account.lamports;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports;
|
||||
let result = nonce_keyed.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
&mut to_keyed,
|
||||
|
@ -651,7 +664,7 @@ mod test {
|
|||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let withdraw_lamports = nonce_keyed.account.lamports + 1;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports + 1;
|
||||
let result = nonce_keyed.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
&mut to_keyed,
|
||||
|
@ -681,7 +694,7 @@ mod test {
|
|||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let withdraw_lamports = nonce_keyed.account.lamports - min_lamports + 1;
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports - min_lamports + 1;
|
||||
let result = nonce_keyed.nonce_withdraw(
|
||||
withdraw_lamports,
|
||||
&mut to_keyed,
|
||||
|
|
|
@ -80,7 +80,8 @@ pub trait Sysvar:
|
|||
if !Self::check_id(keyed_account.unsigned_key()) {
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
Self::from_account(keyed_account.account).ok_or(InstructionError::InvalidArgument)
|
||||
Self::from_account(&*keyed_account.try_account_ref()?)
|
||||
.ok_or(InstructionError::InvalidArgument)
|
||||
}
|
||||
fn create_account(&self, lamports: u64) -> Account {
|
||||
let data_len = Self::size_of().max(bincode::serialized_size(self).unwrap() as usize);
|
||||
|
|
|
@ -21,10 +21,7 @@ pub fn verify_rent_exemption(
|
|||
rent_sysvar_account: &KeyedAccount,
|
||||
) -> Result<(), InstructionError> {
|
||||
let rent = Rent::from_keyed_account(rent_sysvar_account)?;
|
||||
if !rent.is_exempt(
|
||||
keyed_account.account.lamports,
|
||||
keyed_account.account.data.len(),
|
||||
) {
|
||||
if !rent.is_exempt(keyed_account.lamports()?, keyed_account.data_len()?) {
|
||||
Err(InstructionError::InsufficientFunds)
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
|
@ -601,4 +601,29 @@ mod tests {
|
|||
);
|
||||
assert!(tx.is_signed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_instruction_with_duplicate_keys() {
|
||||
let program_id = Pubkey::default();
|
||||
let keypair0 = Keypair::new();
|
||||
let id0 = keypair0.pubkey();
|
||||
let id1 = Pubkey::new_rand();
|
||||
let ix = Instruction::new(
|
||||
program_id,
|
||||
&0,
|
||||
vec![
|
||||
AccountMeta::new(id0, true),
|
||||
AccountMeta::new(id1, false),
|
||||
AccountMeta::new(id0, false),
|
||||
AccountMeta::new(id1, false),
|
||||
],
|
||||
);
|
||||
let mut tx = Transaction::new_unsigned_instructions(vec![ix]);
|
||||
tx.sign(&[&keypair0], Hash::default());
|
||||
assert_eq!(
|
||||
tx.message.instructions[0],
|
||||
CompiledInstruction::new(2, &0, vec![0, 1, 0, 1])
|
||||
);
|
||||
assert!(tx.is_signed());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue