Add system_instruction::{allocate, allocate_with_seed, assign_with_seed}, (#7847)
* cleanup test checks cargo audit * Add system_instruction allocate * fixup * fixup
This commit is contained in:
parent
87598c7612
commit
470d9cd752
|
@ -16,130 +16,89 @@ use solana_sdk::{
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
fn create_account_with_seed(
|
// represents an address that may or may not have been generated
|
||||||
from: &mut KeyedAccount,
|
// from a seed
|
||||||
to: &mut KeyedAccount,
|
#[derive(PartialEq, Default, Debug)]
|
||||||
base: &Pubkey,
|
struct Address {
|
||||||
seed: &str,
|
address: Pubkey,
|
||||||
lamports: u64,
|
base: Option<Pubkey>,
|
||||||
data_length: u64,
|
}
|
||||||
program_id: &Pubkey,
|
|
||||||
|
impl Address {
|
||||||
|
fn is_signer(&self, signers: &HashSet<Pubkey>) -> bool {
|
||||||
|
if let Some(base) = self.base {
|
||||||
|
signers.contains(&base)
|
||||||
|
} else {
|
||||||
|
signers.contains(&self.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn create(
|
||||||
|
address: &Pubkey,
|
||||||
|
with_seed: Option<(&Pubkey, &str, &Pubkey)>,
|
||||||
|
) -> Result<Self, InstructionError> {
|
||||||
|
let base = if let Some((base, seed, program_id)) = with_seed {
|
||||||
|
// re-derive the address, must match the supplied address
|
||||||
|
if *address != create_address_with_seed(base, seed, program_id)? {
|
||||||
|
return Err(SystemError::AddressWithSeedMismatch.into());
|
||||||
|
}
|
||||||
|
Some(*base)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
address: *address,
|
||||||
|
base,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate(
|
||||||
|
account: &mut Account,
|
||||||
|
address: &Address,
|
||||||
|
space: u64,
|
||||||
signers: &HashSet<Pubkey>,
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
// `base` is the source of the derived address and must sign for
|
if !address.is_signer(signers) {
|
||||||
// rights to the address
|
debug!("Allocate: must carry signature of `to`");
|
||||||
if !signers.contains(&base) {
|
|
||||||
debug!("CreateAccountWithSeed: must carry signature of `base`");
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-derive the address, must match the `to` account
|
|
||||||
let address = create_address_with_seed(base, seed, program_id)?;
|
|
||||||
|
|
||||||
if to.unsigned_key() != &address {
|
|
||||||
debug!(
|
|
||||||
"CreateAccountWithSeed: invalid argument; derived {} does not match `to` {}",
|
|
||||||
address,
|
|
||||||
to.unsigned_key()
|
|
||||||
);
|
|
||||||
return Err(SystemError::AddressWithSeedMismatch.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// all of finish_create_account's rules apply
|
|
||||||
finish_create_account(from, to, lamports, data_length, program_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_account(
|
|
||||||
from: &mut KeyedAccount,
|
|
||||||
to: &mut KeyedAccount,
|
|
||||||
lamports: u64,
|
|
||||||
data_length: u64,
|
|
||||||
program_id: &Pubkey,
|
|
||||||
) -> Result<(), InstructionError> {
|
|
||||||
if to.signer_key().is_none() {
|
|
||||||
debug!("CreateAccount: `to` must sign");
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
|
|
||||||
finish_create_account(from, to, lamports, data_length, program_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish_create_account(
|
|
||||||
from: &mut KeyedAccount,
|
|
||||||
to: &mut KeyedAccount,
|
|
||||||
lamports: u64,
|
|
||||||
data_length: u64,
|
|
||||||
program_id: &Pubkey,
|
|
||||||
) -> Result<(), InstructionError> {
|
|
||||||
// if lamports == 0, the `from` account isn't touched
|
|
||||||
if lamports != 0 {
|
|
||||||
if from.signer_key().is_none() {
|
|
||||||
debug!("CreateAccount: `from` must sign transfer");
|
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
|
||||||
}
|
|
||||||
if !from.account.data.is_empty() {
|
|
||||||
debug!("CreateAccount: `from` must not carry data");
|
|
||||||
return Err(InstructionError::InvalidArgument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it looks like the `to` account is already in use, bail
|
// if it looks like the `to` account is already in use, bail
|
||||||
// (note that the id check is also enforced by message_processor)
|
// (note that the id check is also enforced by message_processor)
|
||||||
if !to.account.data.is_empty() || !system_program::check_id(&to.account.owner) {
|
if !account.data.is_empty() || !system_program::check_id(&account.owner) {
|
||||||
debug!(
|
debug!(
|
||||||
"CreateAccount: invalid argument; account {} already in use",
|
"Allocate: invalid argument; account {:?} already in use",
|
||||||
to.unsigned_key()
|
address
|
||||||
);
|
);
|
||||||
return Err(SystemError::AccountAlreadyInUse.into());
|
return Err(SystemError::AccountAlreadyInUse.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if sysvar::is_sysvar_id(&to.unsigned_key()) {
|
if space > MAX_PERMITTED_DATA_LENGTH {
|
||||||
debug!("CreateAccount: account id {} invalid", program_id);
|
|
||||||
return Err(SystemError::InvalidAccountId.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if lamports > from.account.lamports {
|
|
||||||
debug!(
|
debug!(
|
||||||
"CreateAccount: insufficient lamports ({}, need {})",
|
"Allocate: requested space: {} is more than maximum allowed",
|
||||||
from.account.lamports, lamports
|
space
|
||||||
);
|
|
||||||
return Err(SystemError::ResultWithNegativeLamports.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if data_length > MAX_PERMITTED_DATA_LENGTH {
|
|
||||||
debug!(
|
|
||||||
"CreateAccount: requested data_length: {} is more than maximum allowed",
|
|
||||||
data_length
|
|
||||||
);
|
);
|
||||||
return Err(SystemError::InvalidAccountDataLength.into());
|
return Err(SystemError::InvalidAccountDataLength.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// guard against sysvars being made
|
account.data = vec![0; space as usize];
|
||||||
if sysvar::check_id(&program_id) {
|
|
||||||
debug!("Assign: program id {} invalid", program_id);
|
|
||||||
return Err(SystemError::InvalidProgramId.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
to.account.owner = *program_id;
|
|
||||||
|
|
||||||
from.account.lamports -= lamports;
|
|
||||||
to.account.lamports += lamports;
|
|
||||||
to.account.data = vec![0; data_length as usize];
|
|
||||||
to.account.executable = false;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_account_to_program(
|
fn assign(
|
||||||
keyed_account: &mut KeyedAccount,
|
account: &mut Account,
|
||||||
|
address: &Address,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
|
signers: &HashSet<Pubkey>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
// no work to do, just return
|
// no work to do, just return
|
||||||
if keyed_account.account.owner == *program_id {
|
if account.owner == *program_id {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyed_account.signer_key().is_none() {
|
if !address.is_signer(&signers) {
|
||||||
debug!("Assign: account must sign");
|
debug!("Assign: account must sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -150,13 +109,37 @@ fn assign_account_to_program(
|
||||||
return Err(SystemError::InvalidProgramId.into());
|
return Err(SystemError::InvalidProgramId.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
keyed_account.account.owner = *program_id;
|
account.owner = *program_id;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer_lamports(
|
fn allocate_and_assign(
|
||||||
|
to: &mut Account,
|
||||||
|
to_address: &Address,
|
||||||
|
space: u64,
|
||||||
|
program_id: &Pubkey,
|
||||||
|
signers: &HashSet<Pubkey>,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
allocate(to, to_address, space, signers)?;
|
||||||
|
assign(to, to_address, program_id, signers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_account(
|
||||||
from: &mut KeyedAccount,
|
from: &mut KeyedAccount,
|
||||||
to: &mut KeyedAccount,
|
to: &mut Account,
|
||||||
|
to_address: &Address,
|
||||||
|
lamports: u64,
|
||||||
|
space: u64,
|
||||||
|
program_id: &Pubkey,
|
||||||
|
signers: &HashSet<Pubkey>,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
allocate_and_assign(to, to_address, space, program_id, signers)?;
|
||||||
|
transfer(from, to, lamports)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer(
|
||||||
|
from: &mut KeyedAccount,
|
||||||
|
to: &mut Account,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if lamports == 0 {
|
if lamports == 0 {
|
||||||
|
@ -182,7 +165,7 @@ fn transfer_lamports(
|
||||||
}
|
}
|
||||||
|
|
||||||
from.account.lamports -= lamports;
|
from.account.lamports -= lamports;
|
||||||
to.account.lamports += lamports;
|
to.lamports += lamports;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +190,16 @@ pub fn process_instruction(
|
||||||
} => {
|
} => {
|
||||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||||
create_account(from, to, lamports, space, &program_id)
|
let to_address = Address::create(to.unsigned_key(), None)?;
|
||||||
|
create_account(
|
||||||
|
from,
|
||||||
|
to.account,
|
||||||
|
&to_address,
|
||||||
|
lamports,
|
||||||
|
space,
|
||||||
|
&program_id,
|
||||||
|
&signers,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
SystemInstruction::CreateAccountWithSeed {
|
SystemInstruction::CreateAccountWithSeed {
|
||||||
base,
|
base,
|
||||||
|
@ -218,12 +210,13 @@ pub fn process_instruction(
|
||||||
} => {
|
} => {
|
||||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||||
|
let to_address =
|
||||||
|
Address::create(&to.unsigned_key(), Some((&base, &seed, &program_id)))?;
|
||||||
|
|
||||||
create_account_with_seed(
|
create_account(
|
||||||
from,
|
from,
|
||||||
to,
|
to.account,
|
||||||
&base,
|
&to_address,
|
||||||
&seed,
|
|
||||||
lamports,
|
lamports,
|
||||||
space,
|
space,
|
||||||
&program_id,
|
&program_id,
|
||||||
|
@ -231,13 +224,14 @@ pub fn process_instruction(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SystemInstruction::Assign { program_id } => {
|
SystemInstruction::Assign { program_id } => {
|
||||||
let account = next_keyed_account(keyed_accounts_iter)?;
|
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||||
assign_account_to_program(account, &program_id)
|
let address = Address::create(keyed_account.unsigned_key(), None)?;
|
||||||
|
assign(keyed_account.account, &address, &program_id, &signers)
|
||||||
}
|
}
|
||||||
SystemInstruction::Transfer { lamports } => {
|
SystemInstruction::Transfer { lamports } => {
|
||||||
let from = next_keyed_account(keyed_accounts_iter)?;
|
let from = next_keyed_account(keyed_accounts_iter)?;
|
||||||
let to = next_keyed_account(keyed_accounts_iter)?;
|
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||||
transfer_lamports(from, to, lamports)
|
transfer(from, to.account, lamports)
|
||||||
}
|
}
|
||||||
SystemInstruction::AdvanceNonceAccount => {
|
SystemInstruction::AdvanceNonceAccount => {
|
||||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||||
|
@ -269,6 +263,44 @@ pub fn process_instruction(
|
||||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||||
me.nonce_authorize(&nonce_authority, &signers)
|
me.nonce_authorize(&nonce_authority, &signers)
|
||||||
}
|
}
|
||||||
|
SystemInstruction::Allocate { space } => {
|
||||||
|
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||||
|
let address = Address::create(keyed_account.unsigned_key(), None)?;
|
||||||
|
|
||||||
|
allocate(keyed_account.account, &address, space, &signers)
|
||||||
|
}
|
||||||
|
SystemInstruction::AllocateWithSeed {
|
||||||
|
base,
|
||||||
|
seed,
|
||||||
|
space,
|
||||||
|
program_id,
|
||||||
|
} => {
|
||||||
|
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||||
|
let address = Address::create(
|
||||||
|
keyed_account.unsigned_key(),
|
||||||
|
Some((&base, &seed, &program_id)),
|
||||||
|
)?;
|
||||||
|
allocate_and_assign(
|
||||||
|
keyed_account.account,
|
||||||
|
&address,
|
||||||
|
space,
|
||||||
|
&program_id,
|
||||||
|
&signers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SystemInstruction::AssignWithSeed {
|
||||||
|
base,
|
||||||
|
seed,
|
||||||
|
program_id,
|
||||||
|
} => {
|
||||||
|
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
|
||||||
|
let address = Address::create(
|
||||||
|
keyed_account.unsigned_key(),
|
||||||
|
Some((&base, &seed, &program_id)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assign(keyed_account.account, &address, &program_id, &signers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,20 +327,29 @@ pub fn get_system_account_kind(account: &Account) -> Option<SystemAccountKind> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::bank::Bank;
|
use crate::{bank::Bank, bank_client::BankClient};
|
||||||
use crate::bank_client::BankClient;
|
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use solana_sdk::account::Account;
|
use solana_sdk::{
|
||||||
use solana_sdk::client::SyncClient;
|
account::Account,
|
||||||
use solana_sdk::genesis_config::create_genesis_config;
|
client::SyncClient,
|
||||||
use solana_sdk::hash::{hash, Hash};
|
genesis_config::create_genesis_config,
|
||||||
use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError};
|
hash::{hash, Hash},
|
||||||
use solana_sdk::nonce_state;
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
message::Message,
|
||||||
use solana_sdk::system_instruction;
|
nonce_state,
|
||||||
use solana_sdk::system_program;
|
signature::{Keypair, KeypairUtil},
|
||||||
use solana_sdk::sysvar;
|
system_instruction, system_program, sysvar,
|
||||||
use solana_sdk::transaction::TransactionError;
|
transaction::TransactionError,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl From<Pubkey> for Address {
|
||||||
|
fn from(address: Pubkey) -> Self {
|
||||||
|
Self {
|
||||||
|
address,
|
||||||
|
base: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_account() {
|
fn test_create_account() {
|
||||||
|
@ -375,31 +416,18 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_account_with_seed_mismatch() {
|
fn test_address_create_with_seed_mismatch() {
|
||||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
|
||||||
let from = Pubkey::new_rand();
|
let from = Pubkey::new_rand();
|
||||||
let seed = "dull boy";
|
let seed = "dull boy";
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
|
let program_id = Pubkey::new_rand();
|
||||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
|
||||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_account_with_seed(
|
Address::create(&to, Some((&from, seed, &program_id))),
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
|
||||||
&from,
|
|
||||||
seed,
|
|
||||||
50,
|
|
||||||
2,
|
|
||||||
&new_program_owner,
|
|
||||||
&[from].iter().cloned().collect::<HashSet<_>>(),
|
|
||||||
),
|
|
||||||
Err(SystemError::AddressWithSeedMismatch.into())
|
Err(SystemError::AddressWithSeedMismatch.into())
|
||||||
);
|
);
|
||||||
assert_eq!(from_account.lamports, 100);
|
|
||||||
assert_eq!(to_account, Account::default());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_account_with_seed_missing_sig() {
|
fn test_create_account_with_seed_missing_sig() {
|
||||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||||
|
@ -409,17 +437,17 @@ mod tests {
|
||||||
|
|
||||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
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!(
|
assert_eq!(
|
||||||
create_account_with_seed(
|
create_account(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
&mut to_account,
|
||||||
&from,
|
&to_address,
|
||||||
seed,
|
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
&[from].iter().cloned().collect::<HashSet<_>>(),
|
&HashSet::new(),
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
@ -440,10 +468,12 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_account(
|
create_account(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account), // no signer
|
&mut KeyedAccount::new(&from, false, &mut from_account), // no signer
|
||||||
&mut KeyedAccount::new(&to, true, &mut to_account),
|
&mut to_account,
|
||||||
|
&to.into(),
|
||||||
0,
|
0,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[to].iter().cloned().collect::<HashSet<_>>(),
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -467,35 +497,38 @@ mod tests {
|
||||||
|
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
let mut to_account = Account::new(0, 0, &Pubkey::default());
|
||||||
let unchanged_account = to_account.clone();
|
|
||||||
|
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, true, &mut to_account),
|
&mut to_account,
|
||||||
|
&to.into(),
|
||||||
150,
|
150,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[from, to].iter().cloned().collect::<HashSet<_>>(),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
|
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
|
||||||
let from_lamports = from_account.lamports;
|
|
||||||
assert_eq!(from_lamports, 100);
|
|
||||||
assert_eq!(to_account, unchanged_account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_request_more_than_allowed_data_length() {
|
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(100, 0, &system_program::id());
|
||||||
let from_account_key = Pubkey::new_rand();
|
let from = Pubkey::new_rand();
|
||||||
let mut to_account = Account::default();
|
let mut to_account = Account::default();
|
||||||
let to_account_key = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
|
|
||||||
|
let signers = &[from, to].iter().cloned().collect::<HashSet<_>>();
|
||||||
|
let address = &to.into();
|
||||||
|
|
||||||
// Trying to request more data length than permitted will result in failure
|
// Trying to request more data length than permitted will result in failure
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from_account_key, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to_account_key, true, &mut to_account),
|
&mut to_account,
|
||||||
|
&address,
|
||||||
50,
|
50,
|
||||||
MAX_PERMITTED_DATA_LENGTH + 1,
|
MAX_PERMITTED_DATA_LENGTH + 1,
|
||||||
&system_program::id(),
|
&system_program::id(),
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -505,11 +538,13 @@ mod tests {
|
||||||
|
|
||||||
// Trying to request equal or less data length than permitted will be successful
|
// Trying to request equal or less data length than permitted will be successful
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from_account_key, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to_account_key, true, &mut to_account),
|
&mut to_account,
|
||||||
|
&address,
|
||||||
50,
|
50,
|
||||||
MAX_PERMITTED_DATA_LENGTH,
|
MAX_PERMITTED_DATA_LENGTH,
|
||||||
&system_program::id(),
|
&system_program::id(),
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
assert_eq!(to_account.lamports, 50);
|
assert_eq!(to_account.lamports, 50);
|
||||||
|
@ -518,7 +553,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_already_in_use() {
|
fn test_create_already_in_use() {
|
||||||
solana_logger::setup();
|
|
||||||
// Attempt to create system account in account already owned by another program
|
// Attempt to create system account in account already owned by another program
|
||||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||||
let from = Pubkey::new_rand();
|
let from = Pubkey::new_rand();
|
||||||
|
@ -529,12 +563,17 @@ mod tests {
|
||||||
let mut owned_account = Account::new(0, 0, &original_program_owner);
|
let mut owned_account = Account::new(0, 0, &original_program_owner);
|
||||||
let unchanged_account = owned_account.clone();
|
let unchanged_account = owned_account.clone();
|
||||||
|
|
||||||
|
let signers = &[from, owned_key].iter().cloned().collect::<HashSet<_>>();
|
||||||
|
let owned_address = owned_key.into();
|
||||||
|
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, true, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
||||||
|
|
||||||
|
@ -547,10 +586,12 @@ mod tests {
|
||||||
let unchanged_account = owned_account.clone();
|
let unchanged_account = owned_account.clone();
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, true, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
||||||
let from_lamports = from_account.lamports;
|
let from_lamports = from_account.lamports;
|
||||||
|
@ -561,10 +602,12 @@ mod tests {
|
||||||
let mut owned_account = Account::new(1, 0, &Pubkey::default());
|
let mut owned_account = Account::new(1, 0, &Pubkey::default());
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, true, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
assert_eq!(from_account.lamports, from_lamports - 50);
|
assert_eq!(from_account.lamports, from_lamports - 50);
|
||||||
|
@ -580,43 +623,46 @@ mod tests {
|
||||||
|
|
||||||
let owned_key = Pubkey::new_rand();
|
let owned_key = Pubkey::new_rand();
|
||||||
let mut owned_account = Account::new(0, 0, &Pubkey::default());
|
let mut owned_account = Account::new(0, 0, &Pubkey::default());
|
||||||
let unchanged_account = owned_account.clone();
|
|
||||||
|
let owned_address = owned_key.into();
|
||||||
|
|
||||||
// Haven't signed from account
|
// Haven't signed from account
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, true, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[owned_key].iter().cloned().collect::<HashSet<_>>(),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
||||||
assert_eq!(from_account.lamports, 100);
|
|
||||||
assert_eq!(owned_account, unchanged_account);
|
|
||||||
|
|
||||||
// Haven't signed to account
|
// Haven't signed to account
|
||||||
|
let mut owned_account = Account::new(0, 0, &Pubkey::default());
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, false, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[from].iter().cloned().collect::<HashSet<_>>(),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
||||||
assert_eq!(from_account.lamports, 100);
|
|
||||||
assert_eq!(owned_account, unchanged_account);
|
|
||||||
|
|
||||||
// support creation/assignment with zero lamports (ephemeral account)
|
// support creation/assignment with zero lamports (ephemeral account)
|
||||||
|
let mut owned_account = Account::new(0, 0, &Pubkey::default());
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||||
&mut KeyedAccount::new(&owned_key, true, &mut owned_account),
|
&mut owned_account,
|
||||||
|
&owned_address,
|
||||||
0,
|
0,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[owned_key].iter().cloned().collect::<HashSet<_>>(),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
assert_eq!(from_account.lamports, 100);
|
|
||||||
assert_eq!(owned_account.owner, new_program_owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -628,31 +674,21 @@ mod tests {
|
||||||
let to = Pubkey::new_rand();
|
let to = Pubkey::new_rand();
|
||||||
let mut to_account = Account::default();
|
let mut to_account = Account::default();
|
||||||
|
|
||||||
|
let signers = [from, to].iter().cloned().collect::<HashSet<_>>();
|
||||||
|
let to_address = to.into();
|
||||||
|
|
||||||
// fail to create a sysvar::id() owned account
|
// fail to create a sysvar::id() owned account
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, true, &mut to_account),
|
&mut to_account,
|
||||||
|
&to_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&sysvar::id(),
|
&sysvar::id(),
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(result, Err(SystemError::InvalidProgramId.into()));
|
assert_eq!(result, Err(SystemError::InvalidProgramId.into()));
|
||||||
|
|
||||||
let to = sysvar::fees::id();
|
|
||||||
let mut to_account = Account::default();
|
|
||||||
|
|
||||||
// fail to create an account with a sysvar id
|
|
||||||
let result = create_account(
|
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
|
||||||
&mut KeyedAccount::new(&to, true, &mut to_account),
|
|
||||||
50,
|
|
||||||
2,
|
|
||||||
&system_program::id(),
|
|
||||||
);
|
|
||||||
assert_eq!(result, Err(SystemError::InvalidAccountId.into()));
|
|
||||||
|
|
||||||
let from_lamports = from_account.lamports;
|
|
||||||
assert_eq!(from_lamports, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -667,18 +703,23 @@ mod tests {
|
||||||
data: vec![0, 1, 2, 3],
|
data: vec![0, 1, 2, 3],
|
||||||
..Account::default()
|
..Account::default()
|
||||||
};
|
};
|
||||||
let unchanged_account = populated_account.clone();
|
|
||||||
|
let signers = [from, populated_key]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
let populated_address = populated_key.into();
|
||||||
|
|
||||||
let result = create_account(
|
let result = create_account(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&populated_key, true, &mut populated_account),
|
&mut populated_account,
|
||||||
|
&populated_address,
|
||||||
50,
|
50,
|
||||||
2,
|
2,
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&signers,
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
|
||||||
assert_eq!(from_account.lamports, 100);
|
|
||||||
assert_eq!(populated_account, unchanged_account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -697,32 +738,47 @@ mod tests {
|
||||||
let new = Pubkey::new_rand();
|
let new = Pubkey::new_rand();
|
||||||
|
|
||||||
let mut new_account = Account::default();
|
let mut new_account = Account::default();
|
||||||
let mut to = KeyedAccount::new(&new, true, &mut new_account);
|
|
||||||
|
let signers = [nonce, new].iter().cloned().collect::<HashSet<_>>();
|
||||||
|
let new_address = new.into();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_account(&mut from, &mut to, 42, 0, &Pubkey::new_rand()),
|
create_account(
|
||||||
|
&mut from,
|
||||||
|
&mut new_account,
|
||||||
|
&new_address,
|
||||||
|
42,
|
||||||
|
0,
|
||||||
|
&Pubkey::new_rand(),
|
||||||
|
&signers
|
||||||
|
),
|
||||||
Err(InstructionError::InvalidArgument),
|
Err(InstructionError::InvalidArgument),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_assign_account_to_program() {
|
fn test_assign() {
|
||||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||||
|
|
||||||
let from = Pubkey::new_rand();
|
let pubkey = Pubkey::new_rand();
|
||||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
let mut account = Account::new(100, 0, &system_program::id());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
assign_account_to_program(
|
assign(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut account,
|
||||||
|
&pubkey.into(),
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&HashSet::new()
|
||||||
),
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
// no change, no signature needed
|
// no change, no signature needed
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
assign_account_to_program(
|
assign(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut account,
|
||||||
|
&pubkey.into(),
|
||||||
&system_program::id(),
|
&system_program::id(),
|
||||||
|
&HashSet::new()
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
@ -730,7 +786,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&mut [KeyedAccount::new(&from, true, &mut from_account)],
|
&mut [KeyedAccount::new(&pubkey, true, &mut account)],
|
||||||
&bincode::serialize(&SystemInstruction::Assign {
|
&bincode::serialize(&SystemInstruction::Assign {
|
||||||
program_id: new_program_owner
|
program_id: new_program_owner
|
||||||
})
|
})
|
||||||
|
@ -741,16 +797,18 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_assign_account_to_sysvar() {
|
fn test_assign_to_sysvar() {
|
||||||
let new_program_owner = sysvar::id();
|
let new_program_owner = sysvar::id();
|
||||||
|
|
||||||
let from = Pubkey::new_rand();
|
let from = Pubkey::new_rand();
|
||||||
let mut from_account = Account::new(100, 0, &system_program::id());
|
let mut from_account = Account::new(100, 0, &system_program::id());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
assign_account_to_program(
|
assign(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut from_account,
|
||||||
|
&from.into(),
|
||||||
&new_program_owner,
|
&new_program_owner,
|
||||||
|
&[from].iter().cloned().collect::<HashSet<_>>(),
|
||||||
),
|
),
|
||||||
Err(SystemError::InvalidProgramId.into())
|
Err(SystemError::InvalidProgramId.into())
|
||||||
);
|
);
|
||||||
|
@ -783,11 +841,10 @@ mod tests {
|
||||||
fn test_transfer_lamports() {
|
fn test_transfer_lamports() {
|
||||||
let from = Pubkey::new_rand();
|
let from = Pubkey::new_rand();
|
||||||
let mut from_account = Account::new(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter
|
let mut from_account = Account::new(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter
|
||||||
let to = Pubkey::new_rand();
|
|
||||||
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
|
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
|
||||||
transfer_lamports(
|
transfer(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
&mut to_account,
|
||||||
50,
|
50,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -797,9 +854,9 @@ mod tests {
|
||||||
assert_eq!(to_lamports, 51);
|
assert_eq!(to_lamports, 51);
|
||||||
|
|
||||||
// Attempt to move more lamports than remaining in from_account
|
// Attempt to move more lamports than remaining in from_account
|
||||||
let result = transfer_lamports(
|
let result = transfer(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
&mut to_account,
|
||||||
100,
|
100,
|
||||||
);
|
);
|
||||||
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
|
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
|
||||||
|
@ -807,9 +864,9 @@ mod tests {
|
||||||
assert_eq!(to_account.lamports, 51);
|
assert_eq!(to_account.lamports, 51);
|
||||||
|
|
||||||
// test unsigned transfer of zero
|
// test unsigned transfer of zero
|
||||||
assert!(transfer_lamports(
|
assert!(transfer(
|
||||||
&mut KeyedAccount::new(&from, false, &mut from_account),
|
&mut KeyedAccount::new(&from, false, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
&mut to_account,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
.is_ok(),);
|
.is_ok(),);
|
||||||
|
@ -830,18 +887,87 @@ mod tests {
|
||||||
get_system_account_kind(&from_account),
|
get_system_account_kind(&from_account),
|
||||||
Some(SystemAccountKind::Nonce)
|
Some(SystemAccountKind::Nonce)
|
||||||
);
|
);
|
||||||
let to = Pubkey::new_rand();
|
|
||||||
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
|
let mut to_account = Account::new(1, 0, &Pubkey::new(&[3; 32])); // account owner should not matter
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
transfer_lamports(
|
transfer(
|
||||||
&mut KeyedAccount::new(&from, true, &mut from_account),
|
&mut KeyedAccount::new(&from, true, &mut from_account),
|
||||||
&mut KeyedAccount::new(&to, false, &mut to_account),
|
&mut to_account,
|
||||||
50,
|
50,
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidArgument),
|
Err(InstructionError::InvalidArgument),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_allocate() {
|
||||||
|
let (genesis_config, mint_keypair) = create_genesis_config(100);
|
||||||
|
let bank = Bank::new(&genesis_config);
|
||||||
|
let bank_client = BankClient::new(bank);
|
||||||
|
|
||||||
|
let alice_keypair = Keypair::new();
|
||||||
|
let alice_pubkey = alice_keypair.pubkey();
|
||||||
|
let seed = "seed";
|
||||||
|
let program_id = Pubkey::new_rand();
|
||||||
|
let alice_with_seed = create_address_with_seed(&alice_pubkey, seed, &program_id).unwrap();
|
||||||
|
|
||||||
|
bank_client
|
||||||
|
.transfer(50, &mint_keypair, &alice_pubkey)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let allocate_with_seed = Message::new_with_payer(
|
||||||
|
vec![system_instruction::allocate_with_seed(
|
||||||
|
&alice_with_seed,
|
||||||
|
&alice_pubkey,
|
||||||
|
seed,
|
||||||
|
2,
|
||||||
|
&program_id,
|
||||||
|
)],
|
||||||
|
Some(&alice_pubkey),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(bank_client
|
||||||
|
.send_message(&[&alice_keypair], allocate_with_seed)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
let allocate = system_instruction::allocate(&alice_pubkey, 2);
|
||||||
|
|
||||||
|
assert!(bank_client
|
||||||
|
.send_instruction(&alice_keypair, allocate)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_assign_with_seed() {
|
||||||
|
let (genesis_config, mint_keypair) = create_genesis_config(100);
|
||||||
|
let bank = Bank::new(&genesis_config);
|
||||||
|
let bank_client = BankClient::new(bank);
|
||||||
|
|
||||||
|
let alice_keypair = Keypair::new();
|
||||||
|
let alice_pubkey = alice_keypair.pubkey();
|
||||||
|
let seed = "seed";
|
||||||
|
let program_id = Pubkey::new_rand();
|
||||||
|
let alice_with_seed = create_address_with_seed(&alice_pubkey, seed, &program_id).unwrap();
|
||||||
|
|
||||||
|
bank_client
|
||||||
|
.transfer(50, &mint_keypair, &alice_pubkey)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let assign_with_seed = Message::new_with_payer(
|
||||||
|
vec![system_instruction::assign_with_seed(
|
||||||
|
&alice_with_seed,
|
||||||
|
&alice_pubkey,
|
||||||
|
seed,
|
||||||
|
&program_id,
|
||||||
|
)],
|
||||||
|
Some(&alice_pubkey),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(bank_client
|
||||||
|
.send_message(&[&alice_keypair], assign_with_seed)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_unsigned_transaction() {
|
fn test_system_unsigned_transaction() {
|
||||||
let (genesis_config, alice_keypair) = create_genesis_config(100);
|
let (genesis_config, alice_keypair) = create_genesis_config(100);
|
||||||
|
|
|
@ -54,8 +54,8 @@ mkdir -p target/cov/tmp
|
||||||
find target/cov -name \*.gcda -newer "$timing_file" -print0 |
|
find target/cov -name \*.gcda -newer "$timing_file" -print0 |
|
||||||
(while IFS= read -r -d '' gcda_file; do
|
(while IFS= read -r -d '' gcda_file; do
|
||||||
gcno_file="${gcda_file%.gcda}.gcno"
|
gcno_file="${gcda_file%.gcda}.gcno"
|
||||||
ln -s "../../../$gcda_file" "target/cov/tmp/$(basename "$gcda_file")"
|
ln -sf "../../../$gcda_file" "target/cov/tmp/$(basename "$gcda_file")"
|
||||||
ln -s "../../../$gcno_file" "target/cov/tmp/$(basename "$gcno_file")"
|
ln -sf "../../../$gcno_file" "target/cov/tmp/$(basename "$gcno_file")"
|
||||||
done)
|
done)
|
||||||
|
|
||||||
_ grcov target/cov/tmp > target/cov/lcov-full.info
|
_ grcov target/cov/tmp > target/cov/lcov-full.info
|
||||||
|
|
|
@ -13,7 +13,6 @@ pub enum SystemError {
|
||||||
AccountAlreadyInUse,
|
AccountAlreadyInUse,
|
||||||
ResultWithNegativeLamports,
|
ResultWithNegativeLamports,
|
||||||
InvalidProgramId,
|
InvalidProgramId,
|
||||||
InvalidAccountId,
|
|
||||||
InvalidAccountDataLength,
|
InvalidAccountDataLength,
|
||||||
InvalidSeed,
|
InvalidSeed,
|
||||||
MaxSeedLengthExceeded,
|
MaxSeedLengthExceeded,
|
||||||
|
@ -63,7 +62,7 @@ pub enum SystemInstruction {
|
||||||
/// * Transaction::keys[0] - source
|
/// * Transaction::keys[0] - source
|
||||||
/// * Transaction::keys[1] - new account key
|
/// * Transaction::keys[1] - new account key
|
||||||
/// * lamports - number of lamports to transfer to the new account
|
/// * lamports - number of lamports to transfer to the new account
|
||||||
/// * space - memory to allocate if greater then zero
|
/// * space - number of bytes of memory to allocate
|
||||||
/// * program_id - the program id of the new account
|
/// * program_id - the program id of the new account
|
||||||
CreateAccount {
|
CreateAccount {
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
|
@ -78,12 +77,12 @@ pub enum SystemInstruction {
|
||||||
/// * Transaction::keys[1] - destination
|
/// * Transaction::keys[1] - destination
|
||||||
Transfer { lamports: u64 },
|
Transfer { lamports: u64 },
|
||||||
/// Create a new account at an address derived from
|
/// Create a new account at an address derived from
|
||||||
/// the from account and a seed
|
/// a base pubkey and a seed
|
||||||
/// * Transaction::keys[0] - source
|
/// * Transaction::keys[0] - source
|
||||||
/// * Transaction::keys[1] - new account key
|
/// * Transaction::keys[1] - new account key
|
||||||
/// * seed - string of ascii chars, no longer than MAX_ADDRESS_SEED_LEN
|
/// * seed - string of ascii chars, no longer than MAX_ADDRESS_SEED_LEN
|
||||||
/// * lamports - number of lamports to transfer to the new account
|
/// * lamports - number of lamports to transfer to the new account
|
||||||
/// * space - memory to allocate if greater then zero
|
/// * space - number of bytes of memory to allocate
|
||||||
/// * program_id - the program id of the new account
|
/// * program_id - the program id of the new account
|
||||||
CreateAccountWithSeed {
|
CreateAccountWithSeed {
|
||||||
base: Pubkey,
|
base: Pubkey,
|
||||||
|
@ -137,6 +136,31 @@ pub enum SystemInstruction {
|
||||||
///
|
///
|
||||||
/// The current authority must sign a transaction executing this instruction
|
/// The current authority must sign a transaction executing this instruction
|
||||||
AuthorizeNonceAccount(Pubkey),
|
AuthorizeNonceAccount(Pubkey),
|
||||||
|
/// Allocate space in a (possibly new) account without funding
|
||||||
|
/// * Transaction::keys[0] - new account key
|
||||||
|
/// * space - number of bytes of memory to allocate
|
||||||
|
Allocate { space: u64 },
|
||||||
|
/// Allocate space for and assign an account at an address
|
||||||
|
/// derived from a base pubkey and a seed
|
||||||
|
/// * Transaction::keys[0] - new account key
|
||||||
|
/// * seed - string of ascii chars, no longer than MAX_ADDRESS_SEED_LEN
|
||||||
|
/// * space - number of bytes of memory to allocate
|
||||||
|
/// * program_id - the program id of the new account
|
||||||
|
AllocateWithSeed {
|
||||||
|
base: Pubkey,
|
||||||
|
seed: String,
|
||||||
|
space: u64,
|
||||||
|
program_id: Pubkey,
|
||||||
|
},
|
||||||
|
/// Assign account to a program based on a seed
|
||||||
|
/// * Transaction::keys[0] - account to assign
|
||||||
|
/// * seed - string of ascii chars, no longer than MAX_ADDRESS_SEED_LEN
|
||||||
|
/// * program_id - the program id of the new account
|
||||||
|
AssignWithSeed {
|
||||||
|
base: Pubkey,
|
||||||
|
seed: String,
|
||||||
|
program_id: Pubkey,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_account(
|
pub fn create_account(
|
||||||
|
@ -191,8 +215,8 @@ pub fn create_account_with_seed(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign(from_pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
pub fn assign(pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
||||||
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
let account_metas = vec![AccountMeta::new(*pubkey, true)];
|
||||||
Instruction::new(
|
Instruction::new(
|
||||||
system_program::id(),
|
system_program::id(),
|
||||||
&SystemInstruction::Assign {
|
&SystemInstruction::Assign {
|
||||||
|
@ -202,6 +226,24 @@ pub fn assign(from_pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn assign_with_seed(
|
||||||
|
address: &Pubkey, // must match create_address_with_seed(base, seed, program_id)
|
||||||
|
base: &Pubkey,
|
||||||
|
seed: &str,
|
||||||
|
program_id: &Pubkey,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = vec![AccountMeta::new(*address, false)].with_signer(base);
|
||||||
|
Instruction::new(
|
||||||
|
system_program::id(),
|
||||||
|
&SystemInstruction::AssignWithSeed {
|
||||||
|
base: *base,
|
||||||
|
seed: seed.to_string(),
|
||||||
|
program_id: *program_id,
|
||||||
|
},
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
||||||
let account_metas = vec![
|
let account_metas = vec![
|
||||||
AccountMeta::new(*from_pubkey, true),
|
AccountMeta::new(*from_pubkey, true),
|
||||||
|
@ -214,6 +256,35 @@ pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Inst
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allocate(pubkey: &Pubkey, space: u64) -> Instruction {
|
||||||
|
let account_metas = vec![AccountMeta::new(*pubkey, true)];
|
||||||
|
Instruction::new(
|
||||||
|
system_program::id(),
|
||||||
|
&SystemInstruction::Allocate { space },
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_with_seed(
|
||||||
|
address: &Pubkey, // must match create_address_with_seed(base, seed, program_id)
|
||||||
|
base: &Pubkey,
|
||||||
|
seed: &str,
|
||||||
|
space: u64,
|
||||||
|
program_id: &Pubkey,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = vec![AccountMeta::new(*address, false)].with_signer(base);
|
||||||
|
Instruction::new(
|
||||||
|
system_program::id(),
|
||||||
|
&SystemInstruction::AllocateWithSeed {
|
||||||
|
base: *base,
|
||||||
|
seed: seed.to_string(),
|
||||||
|
space,
|
||||||
|
program_id: *program_id,
|
||||||
|
},
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create and sign new SystemInstruction::Transfer transaction to many destinations
|
/// Create and sign new SystemInstruction::Transfer transaction to many destinations
|
||||||
pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec<Instruction> {
|
pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec<Instruction> {
|
||||||
to_lamports
|
to_lamports
|
||||||
|
@ -223,7 +294,7 @@ pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_address_with_seed(
|
pub fn create_address_with_seed(
|
||||||
from_pubkey: &Pubkey,
|
base: &Pubkey,
|
||||||
seed: &str,
|
seed: &str,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
) -> Result<Pubkey, SystemError> {
|
) -> Result<Pubkey, SystemError> {
|
||||||
|
@ -232,7 +303,7 @@ pub fn create_address_with_seed(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Pubkey::new(
|
Ok(Pubkey::new(
|
||||||
hashv(&[from_pubkey.as_ref(), seed.as_ref(), program_id.as_ref()]).as_ref(),
|
hashv(&[base.as_ref(), seed.as_ref(), program_id.as_ref()]).as_ref(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue