solana/runtime/src/system_program.rs

314 lines
12 KiB
Rust
Raw Normal View History

2019-03-11 15:35:25 -07:00
use bincode::serialize;
2018-12-14 20:39:10 -08:00
use log::*;
2018-12-03 13:32:31 -08:00
use solana_sdk::account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
2019-03-13 13:37:24 -07:00
use solana_sdk::system_instruction::{SystemError, SystemInstruction};
2018-12-03 13:32:31 -08:00
use solana_sdk::system_program;
use solana_sdk::transaction::InstructionError;
2018-12-03 13:32:31 -08:00
const FROM_ACCOUNT_INDEX: usize = 0;
const TO_ACCOUNT_INDEX: usize = 1;
fn create_system_account(
keyed_accounts: &mut [KeyedAccount],
2019-03-05 16:28:14 -08:00
lamports: u64,
space: u64,
program_id: &Pubkey,
) -> Result<(), SystemError> {
if !system_program::check_id(&keyed_accounts[FROM_ACCOUNT_INDEX].account.owner) {
info!("CreateAccount: invalid account[from] owner");
Err(SystemError::SourceNotSystemAccount)?;
}
if !keyed_accounts[TO_ACCOUNT_INDEX].account.data.is_empty()
|| !system_program::check_id(&keyed_accounts[TO_ACCOUNT_INDEX].account.owner)
{
info!(
"CreateAccount: invalid argument; account {} already in use",
keyed_accounts[TO_ACCOUNT_INDEX].unsigned_key()
);
Err(SystemError::AccountAlreadyInUse)?;
}
2019-03-05 16:28:14 -08:00
if lamports > keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports {
info!(
2019-03-05 16:28:14 -08:00
"CreateAccount: insufficient lamports ({}, need {})",
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports, lamports
);
2019-03-05 16:28:14 -08:00
Err(SystemError::ResultWithNegativeLamports)?;
}
2019-03-05 16:28:14 -08:00
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports -= lamports;
keyed_accounts[TO_ACCOUNT_INDEX].account.lamports += lamports;
keyed_accounts[TO_ACCOUNT_INDEX].account.owner = *program_id;
keyed_accounts[TO_ACCOUNT_INDEX].account.data = vec![0; space as usize];
keyed_accounts[TO_ACCOUNT_INDEX].account.executable = false;
Ok(())
}
fn assign_account_to_program(
keyed_accounts: &mut [KeyedAccount],
program_id: &Pubkey,
2019-03-13 11:28:54 -07:00
) -> Result<(), SystemError> {
keyed_accounts[FROM_ACCOUNT_INDEX].account.owner = *program_id;
Ok(())
}
2019-03-13 11:28:54 -07:00
fn move_lamports(keyed_accounts: &mut [KeyedAccount], lamports: u64) -> Result<(), SystemError> {
2019-03-05 16:28:14 -08:00
if lamports > keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports {
info!(
2019-03-05 16:28:14 -08:00
"Move: insufficient lamports ({}, need {})",
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports, lamports
);
2019-03-13 11:28:54 -07:00
Err(SystemError::ResultWithNegativeLamports)?;
}
2019-03-05 16:28:14 -08:00
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports -= lamports;
keyed_accounts[TO_ACCOUNT_INDEX].account.lamports += lamports;
Ok(())
}
pub fn entrypoint(
2018-12-03 13:32:31 -08:00
_program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
_tick_height: u64,
) -> Result<(), InstructionError> {
2019-03-13 11:28:54 -07:00
if let Ok(instruction) = bincode::deserialize(data) {
trace!("process_instruction: {:?}", instruction);
2018-12-03 13:32:31 -08:00
trace!("keyed_accounts: {:?}", keyed_accounts);
// All system instructions require that accounts_keys[0] be a signer
if keyed_accounts[FROM_ACCOUNT_INDEX].signer_key().is_none() {
2018-12-03 13:32:31 -08:00
info!("account[from] is unsigned");
Err(InstructionError::MissingRequiredSignature)?;
2018-12-03 13:32:31 -08:00
}
2019-03-13 11:28:54 -07:00
match instruction {
2018-12-03 13:32:31 -08:00
SystemInstruction::CreateAccount {
2019-03-05 16:28:14 -08:00
lamports,
2018-12-03 13:32:31 -08:00
space,
program_id,
2019-03-13 11:28:54 -07:00
} => create_system_account(keyed_accounts, lamports, space, &program_id),
2018-12-03 13:32:31 -08:00
SystemInstruction::Assign { program_id } => {
2019-03-13 11:28:54 -07:00
if !system_program::check_id(&keyed_accounts[FROM_ACCOUNT_INDEX].account.owner) {
Err(InstructionError::IncorrectProgramId)?;
2019-03-13 11:28:54 -07:00
}
assign_account_to_program(keyed_accounts, &program_id)
2018-12-03 13:32:31 -08:00
}
2019-03-05 16:28:14 -08:00
SystemInstruction::Move { lamports } => move_lamports(keyed_accounts, lamports),
2018-12-03 13:32:31 -08:00
}
.map_err(|e| InstructionError::CustomError(serialize(&e).unwrap()))
2018-12-03 13:32:31 -08:00
} else {
info!("Invalid instruction data: {:?}", data);
Err(InstructionError::InvalidInstructionData)
}
}
#[cfg(test)]
mod tests {
use super::*;
2019-03-16 16:37:18 -07:00
use crate::bank::Bank;
use crate::bank_client::BankClient;
use solana_sdk::account::Account;
2019-03-16 16:37:18 -07:00
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::script::Script;
use solana_sdk::signature::{Keypair, KeypairUtil};
2019-03-16 16:37:18 -07:00
use solana_sdk::system_instruction::SystemInstruction;
use solana_sdk::system_program;
2019-03-19 12:03:20 -07:00
use solana_sdk::transaction::{AccountMeta, Instruction, InstructionError, TransactionError};
#[test]
fn test_create_system_account() {
let new_program_owner = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &system_program::id());
2019-03-05 13:43:05 -08:00
let to = Keypair::new().pubkey();
let mut to_account = Account::new(0, 0, &Pubkey::default());
2019-03-05 13:43:05 -08:00
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&to, false, &mut to_account),
];
create_system_account(&mut keyed_accounts, 50, 2, &new_program_owner).unwrap();
2019-03-05 16:28:14 -08:00
let from_lamports = from_account.lamports;
let to_lamports = to_account.lamports;
let to_owner = to_account.owner;
let to_data = to_account.data.clone();
2019-03-05 16:28:14 -08:00
assert_eq!(from_lamports, 50);
assert_eq!(to_lamports, 50);
assert_eq!(to_owner, new_program_owner);
assert_eq!(to_data, [0, 0]);
2019-03-05 13:43:05 -08:00
}
2019-03-05 13:43:05 -08:00
#[test]
2019-03-05 16:28:14 -08:00
fn test_create_negative_lamports() {
// Attempt to create account with more lamports than remaining in from_account
2019-03-05 13:43:05 -08:00
let new_program_owner = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &system_program::id());
2019-03-05 13:43:05 -08:00
let to = Keypair::new().pubkey();
let mut to_account = Account::new(0, 0, &Pubkey::default());
let unchanged_account = to_account.clone();
2019-03-05 13:43:05 -08:00
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&to, false, &mut to_account),
];
let result = create_system_account(&mut keyed_accounts, 150, 2, &new_program_owner);
2019-03-05 16:28:14 -08:00
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports));
let from_lamports = from_account.lamports;
assert_eq!(from_lamports, 100);
assert_eq!(to_account, unchanged_account);
2019-03-05 13:43:05 -08:00
}
2019-03-05 13:43:05 -08:00
#[test]
fn test_create_already_owned() {
// Attempt to create system account in account already owned by another program
2019-03-05 13:43:05 -08:00
let new_program_owner = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &system_program::id());
2019-03-05 13:43:05 -08:00
let original_program_owner = Pubkey::new(&[5; 32]);
let owned_key = Keypair::new().pubkey();
let mut owned_account = Account::new(0, 0, &original_program_owner);
let unchanged_account = owned_account.clone();
2019-03-05 13:43:05 -08:00
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&owned_key, false, &mut owned_account),
];
let result = create_system_account(&mut keyed_accounts, 50, 2, &new_program_owner);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse));
2019-03-05 16:28:14 -08:00
let from_lamports = from_account.lamports;
assert_eq!(from_lamports, 100);
assert_eq!(owned_account, unchanged_account);
2019-03-05 13:43:05 -08:00
}
2019-03-05 13:43:05 -08:00
#[test]
fn test_create_data_populated() {
// Attempt to create system account in account with populated data
2019-03-05 13:43:05 -08:00
let new_program_owner = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &system_program::id());
2019-03-05 13:43:05 -08:00
let populated_key = Keypair::new().pubkey();
let mut populated_account = Account {
2019-03-05 16:28:14 -08:00
lamports: 0,
data: vec![0, 1, 2, 3],
owner: Pubkey::default(),
executable: false,
};
let unchanged_account = populated_account.clone();
2019-03-05 13:43:05 -08:00
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&populated_key, false, &mut populated_account),
];
let result = create_system_account(&mut keyed_accounts, 50, 2, &new_program_owner);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse));
2019-03-05 16:28:14 -08:00
assert_eq!(from_account.lamports, 100);
assert_eq!(populated_account, unchanged_account);
}
#[test]
fn test_create_not_system_account() {
let other_program = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &other_program);
let to = Keypair::new().pubkey();
let mut to_account = Account::new(0, 0, &Pubkey::default());
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&to, false, &mut to_account),
];
let result = create_system_account(&mut keyed_accounts, 50, 2, &other_program);
assert_eq!(result, Err(SystemError::SourceNotSystemAccount));
}
#[test]
fn test_assign_account_to_program() {
let new_program_owner = Pubkey::new(&[9; 32]);
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &system_program::id());
let mut keyed_accounts = [KeyedAccount::new(&from, true, &mut from_account)];
assign_account_to_program(&mut keyed_accounts, &new_program_owner).unwrap();
let from_owner = from_account.owner;
assert_eq!(from_owner, new_program_owner);
// Attempt to assign account not owned by system program
let another_program_owner = Pubkey::new(&[8; 32]);
keyed_accounts = [KeyedAccount::new(&from, true, &mut from_account)];
2019-03-13 11:28:54 -07:00
let instruction = SystemInstruction::Assign {
program_id: another_program_owner,
};
let data = serialize(&instruction).unwrap();
let result = entrypoint(&system_program::id(), &mut keyed_accounts, &data, 0);
assert_eq!(result, Err(InstructionError::IncorrectProgramId));
assert_eq!(from_account.owner, new_program_owner);
}
#[test]
2019-03-05 16:28:14 -08:00
fn test_move_lamports() {
let from = Keypair::new().pubkey();
let mut from_account = Account::new(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter
let to = Keypair::new().pubkey();
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
let mut keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&to, false, &mut to_account),
];
2019-03-05 16:28:14 -08:00
move_lamports(&mut keyed_accounts, 50).unwrap();
let from_lamports = from_account.lamports;
let to_lamports = to_account.lamports;
assert_eq!(from_lamports, 50);
assert_eq!(to_lamports, 51);
2019-03-05 16:28:14 -08:00
// Attempt to move more lamports than remaining in from_account
keyed_accounts = [
KeyedAccount::new(&from, true, &mut from_account),
KeyedAccount::new(&to, false, &mut to_account),
];
2019-03-05 16:28:14 -08:00
let result = move_lamports(&mut keyed_accounts, 100);
2019-03-13 11:28:54 -07:00
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports));
2019-03-05 16:28:14 -08:00
assert_eq!(from_account.lamports, 50);
assert_eq!(to_account.lamports, 51);
2018-12-03 13:32:31 -08:00
}
2019-03-16 16:37:18 -07:00
#[test]
fn test_system_unsigned_transaction() {
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);
let alice_pubkey = alice_client.pubkey();
let mallory_client = BankClient::new(&bank, Keypair::new());
let mallory_pubkey = mallory_client.pubkey();
// Fund to account to bypass AccountNotFound error
alice_client.transfer(50, &mallory_pubkey).unwrap();
// Erroneously sign transaction with recipient account key
// No signature case is tested by bank `test_zero_signatures()`
2019-03-19 12:03:20 -07:00
let account_metas = vec![
AccountMeta(alice_pubkey, false),
AccountMeta(mallory_pubkey, true),
];
let malicious_script = Script::new(vec![Instruction::new(
2019-03-16 16:37:18 -07:00
system_program::id(),
&SystemInstruction::Move { lamports: 10 },
2019-03-19 12:03:20 -07:00
account_metas,
)]);
2019-03-16 16:37:18 -07:00
assert_eq!(
mallory_client.process_script(malicious_script),
Err(TransactionError::InstructionError(
0,
InstructionError::MissingRequiredSignature
2019-03-16 16:37:18 -07:00
))
);
assert_eq!(bank.get_balance(&alice_pubkey), 50);
assert_eq!(bank.get_balance(&mallory_pubkey), 50);
}
2018-12-03 13:32:31 -08:00
}