verify signature is on the from account
This commit is contained in:
parent
fa4bdb4613
commit
e7b0a736f5
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue