Skip to content

Commit

Permalink
Remove create account bandaid now that requires signature
Browse files Browse the repository at this point in the history
  • Loading branch information
rob-solana committed Jan 14, 2020
1 parent b5dba77 commit e130bfe
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 9 deletions.
79 changes: 72 additions & 7 deletions runtime/src/system_instruction_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,8 @@ fn finish_create_account(
}

// if it looks like the `to` account is already in use, bail
if to.account.lamports != 0
|| !to.account.data.is_empty()
|| !system_program::check_id(&to.account.owner)
{
// (note that the id check is also enforced by message_processor)
if !to.account.data.is_empty() || !system_program::check_id(&to.account.owner) {
debug!(
"CreateAccount: invalid argument; account {} already in use",
to.unsigned_key()
Expand Down Expand Up @@ -116,7 +114,7 @@ fn finish_create_account(
return Err(SystemError::InvalidAccountDataLength.into());
}

// guard against sysvars being assigned
// guard against sysvars being made
if sysvar::check_id(&program_id) {
debug!("Assign: program id {} invalid", program_id);
return Err(SystemError::InvalidProgramId.into());
Expand All @@ -136,12 +134,17 @@ fn assign_account_to_program(
account: &mut KeyedAccount,
program_id: &Pubkey,
) -> Result<(), InstructionError> {
// no work to do, just return
if account.account.owner == *program_id {
return Ok(());
}

if account.signer_key().is_none() {
debug!("Assign: account must sign");
return Err(InstructionError::MissingRequiredSignature);
}

// guard against sysvars being assigned
// guard against sysvars being made
if sysvar::check_id(&program_id) {
debug!("Assign: program id {} invalid", program_id);
return Err(SystemError::InvalidProgramId.into());
Expand Down Expand Up @@ -515,6 +518,7 @@ mod tests {

#[test]
fn test_create_already_in_use() {
solana_logger::setup();
// 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();
Expand All @@ -538,7 +542,8 @@ mod tests {
assert_eq!(from_lamports, 100);
assert_eq!(owned_account, unchanged_account);

let mut owned_account = Account::new(10, 0, &Pubkey::default());
// Attempt to create system account in account that already has data
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),
Expand All @@ -551,6 +556,19 @@ mod tests {
let from_lamports = from_account.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(&owned_key, true, &mut owned_account),
50,
2,
&new_program_owner,
);
assert_eq!(result, Ok(()));
assert_eq!(from_account.lamports, from_lamports - 50);
assert_eq!(owned_account.lamports, 1 + 50);
}

#[test]
Expand Down Expand Up @@ -700,6 +718,14 @@ mod tests {
),
Err(InstructionError::MissingRequiredSignature)
);
// no change, no signature needed
assert_eq!(
assign_account_to_program(
&mut KeyedAccount::new(&from, false, &mut from_account),
&system_program::id(),
),
Ok(())
);

assert_eq!(
process_instruction(
Expand Down Expand Up @@ -816,6 +842,45 @@ mod tests {
)
}

#[test]
fn test_create_account_no_transfer() {
solana_logger::setup();
let (genesis_config, alice_keypair) = create_genesis_config(100);
let alice_pubkey = alice_keypair.pubkey();
let bob_keypair = Keypair::new();
let bob_pubkey = bob_keypair.pubkey();

// Fund to account to bypass AccountNotFound error
let bank = Bank::new(&genesis_config);
let bank_client = BankClient::new(bank);
bank_client
.transfer(50, &alice_keypair, &bob_pubkey)
.unwrap();
let program_id = Pubkey::new_rand();

// test system_instruction: that alice's signature is not asked for
let instruction =
system_instruction::create_account(&alice_pubkey, &bob_pubkey, 0, 1, &program_id);

assert!(!instruction.accounts[0].is_signer);

// test system_instruction_processor: that alice's signature is needed
assert!(bank_client
.send_instruction(&bob_keypair, instruction)
.is_ok());

assert_eq!(bank_client.get_balance(&alice_pubkey).unwrap(), 50);
assert_eq!(
bank_client.get_account(&bob_pubkey).unwrap().unwrap(),
Account {
data: vec![0; 1],
owner: program_id,
lamports: 50,
..Account::default()
}
);
}

#[test]
fn test_system_unsigned_transaction() {
let (genesis_config, alice_keypair) = create_genesis_config(100);
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/system_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ pub fn create_account(
program_id: &Pubkey,
) -> Instruction {
let account_metas = vec![
AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*from_pubkey, lamports != 0), // no signature required if no transfer
AccountMeta::new(*to_pubkey, true),
];
Instruction::new(
Expand All @@ -173,7 +173,7 @@ pub fn create_account_with_seed(
program_id: &Pubkey,
) -> Instruction {
let account_metas = vec![
AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*from_pubkey, lamports != 0),
AccountMeta::new(*to_pubkey, false),
]
.with_signer(base);
Expand Down

0 comments on commit e130bfe

Please sign in to comment.