verify signature is on the from account

This commit is contained in:
Rob Walker 2018-11-27 23:58:41 -08:00
parent fa4bdb4613
commit e7b0a736f5
1 changed files with 81 additions and 30 deletions

View File

@ -36,64 +36,80 @@ pub fn id() -> Pubkey {
pub fn get_balance(account: &Account) -> u64 {
account.tokens
}
pub fn process_instruction(
tx: &Transaction,
pix: usize,
accounts: &mut [&mut Account],
) -> Result<()> {
fn process_instruction(tx: &Transaction, pix: usize, accounts: &mut [&mut Account]) -> Result<()> {
if let Ok(syscall) = deserialize(tx.userdata(pix)) {
trace!("process_instruction: {:?}", syscall);
let from = 0;
// all system instructions require that accounts_keys[0] be a signer
if tx.signed_key(pix, from).is_none() {
Err(Error::InvalidArgument)?;
}
match syscall {
SystemInstruction::CreateAccount {
tokens,
space,
program_id,
} => {
if !check_id(&accounts[0].owner) {
info!("Invalid account[0] owner");
let to = 1;
if !check_id(&accounts[from].owner) {
info!("CreateAccount: invalid account[from] owner");
Err(Error::InvalidArgument)?;
}
if space > 0 && (!accounts[1].userdata.is_empty() || !check_id(&accounts[1].owner))
if space > 0
&& (!accounts[to].userdata.is_empty() || !check_id(&accounts[to].owner))
{
info!("Invalid account[1]");
info!(
"CreateAccount: invalid argument space: {} accounts.userdata.len(): {}",
space,
accounts[to].userdata.len(),
);
Err(Error::InvalidArgument)?;
}
if tokens > accounts[0].tokens {
if tokens > accounts[from].tokens {
info!(
"Insufficient tokens in account[0] ({} > {})",
tokens, accounts[0].tokens
"CreateAccount: insufficient tokens ({}, need {})",
accounts[from].tokens, tokens
);
Err(Error::ResultWithNegativeTokens)?;
}
accounts[0].tokens -= tokens;
accounts[1].tokens += tokens;
accounts[1].owner = program_id;
accounts[1].userdata = vec![0; space as usize];
accounts[1].executable = false;
accounts[1].loader = Pubkey::default();
accounts[from].tokens -= tokens;
accounts[to].tokens += tokens;
accounts[to].owner = program_id;
accounts[to].userdata = vec![0; space as usize];
accounts[to].executable = false;
accounts[to].loader = Pubkey::default();
}
SystemInstruction::Assign { program_id } => {
if !check_id(&accounts[0].owner) {
if !check_id(&accounts[from].owner) {
Err(Error::AssignOfUnownedAccount)?;
}
accounts[0].owner = program_id;
accounts[from].owner = program_id;
}
SystemInstruction::Move { tokens } => {
let to = 1;
//bank should be verifying correctness
if tokens > accounts[0].tokens {
info!("Insufficient tokens in account[0]");
if tokens > accounts[from].tokens {
info!(
"Move: insufficient tokens ({}, need {})",
accounts[from].tokens, tokens
);
Err(Error::ResultWithNegativeTokens)?;
}
accounts[0].tokens -= tokens;
accounts[1].tokens += tokens;
accounts[from].tokens -= tokens;
accounts[to].tokens += tokens;
}
SystemInstruction::Spawn => {
if !accounts[0].executable || accounts[0].loader != Pubkey::default() {
if !accounts[from].executable || accounts[from].loader != Pubkey::default() {
Err(Error::AccountNotFinalized)?;
}
accounts[0].loader = accounts[0].owner;
accounts[0].owner = tx.account_keys[0];
accounts[from].loader = accounts[from].owner;
accounts[from].owner = tx.account_keys[from];
}
}
Ok(())
@ -124,9 +140,30 @@ mod test {
use system_transaction::SystemTransaction;
use transaction::Transaction;
/// Execute a function with a subset of accounts as writable references.
/// Since the subset can point to the same references, in any order there is no way
/// for the borrow checker to track them with regards to the original set.
fn with_subset<F, A>(accounts: &mut [Account], ixes: &[u8], func: F) -> A
where
F: FnOnce(&mut [&mut Account]) -> A,
{
let mut subset: Vec<&mut Account> = ixes
.iter()
.map(|ix| {
let ptr = &mut accounts[*ix as usize] as *mut Account;
// lifetime of this unsafe is only within the scope of the closure
// there is no way to reorder them without breaking borrow checker rules
unsafe { &mut *ptr }
}).collect();
func(&mut subset)
}
fn process_transaction(tx: &Transaction, accounts: &mut [Account]) -> Result<()> {
let mut refs: Vec<&mut Account> = accounts.iter_mut().collect();
super::process_instruction(&tx, 0, &mut refs[..])
for (instruction_index, instruction) in tx.instructions.iter().enumerate() {
with_subset(accounts, &instruction.accounts, |mut program_accounts| {
super::process_instruction(tx, instruction_index, &mut program_accounts)
})?;
}
Ok(())
}
#[test]
@ -251,7 +288,21 @@ mod test {
assert_eq!(accounts[0].tokens, 0);
assert_eq!(accounts[1].tokens, 1);
}
/// Detect binary changes in the serialized program userdata, which could have a downstream
#[test]
fn test_move_many() {
let from = Keypair::new();
let tos = [(Keypair::new().pubkey(), 2), (Keypair::new().pubkey(), 1)];
let mut accounts = vec![Account::default(), Account::default(), Account::default()];
accounts[0].tokens = 3;
let tx = Transaction::system_move_many(&from, &tos, Hash::default(), 0);
process_transaction(&tx, &mut accounts).unwrap();
assert_eq!(accounts[0].tokens, 0);
assert_eq!(accounts[1].tokens, 2);
assert_eq!(accounts[2].tokens, 1);
}
// Detect binary changes in the serialized program userdata, which could have a downstream
/// affect on SDKs and DApps
#[test]
fn test_sdk_serialize() {