2019-03-23 21:12:27 -06:00
|
|
|
use crate::instruction::{AccountMeta, Instruction};
|
2019-04-25 11:29:44 -06:00
|
|
|
use crate::instruction_processor_utils::DecodeError;
|
2018-12-14 20:39:10 -08:00
|
|
|
use crate::pubkey::Pubkey;
|
2019-02-28 04:48:44 -07:00
|
|
|
use crate::system_program;
|
2019-04-25 11:29:44 -06:00
|
|
|
use num_derive::FromPrimitive;
|
2018-11-16 08:04:46 -08:00
|
|
|
|
2019-04-25 11:29:44 -06:00
|
|
|
#[derive(Serialize, Debug, Clone, PartialEq, FromPrimitive)]
|
2019-03-13 14:37:24 -06:00
|
|
|
pub enum SystemError {
|
|
|
|
AccountAlreadyInUse,
|
|
|
|
ResultWithNegativeLamports,
|
|
|
|
SourceNotSystemAccount,
|
2019-06-06 19:27:49 -07:00
|
|
|
InvalidProgramId,
|
|
|
|
InvalidAccountId,
|
2019-03-13 14:37:24 -06:00
|
|
|
}
|
|
|
|
|
2019-04-25 11:29:44 -06:00
|
|
|
impl<T> DecodeError<T> for SystemError {
|
|
|
|
fn type_of(&self) -> &'static str {
|
|
|
|
"SystemError"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for SystemError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl std::error::Error for SystemError {}
|
|
|
|
|
2019-01-14 18:21:42 -07:00
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
2018-11-16 08:04:46 -08:00
|
|
|
pub enum SystemInstruction {
|
|
|
|
/// Create a new account
|
|
|
|
/// * Transaction::keys[0] - source
|
|
|
|
/// * Transaction::keys[1] - new account key
|
2019-03-05 16:28:14 -08:00
|
|
|
/// * lamports - number of lamports to transfer to the new account
|
2018-11-16 08:04:46 -08:00
|
|
|
/// * space - memory to allocate if greater then zero
|
|
|
|
/// * program_id - the program id of the new account
|
|
|
|
CreateAccount {
|
2019-03-05 16:28:14 -08:00
|
|
|
lamports: u64,
|
2018-11-16 08:04:46 -08:00
|
|
|
space: u64,
|
|
|
|
program_id: Pubkey,
|
|
|
|
},
|
|
|
|
/// Assign account to a program
|
|
|
|
/// * Transaction::keys[0] - account to assign
|
|
|
|
Assign { program_id: Pubkey },
|
2019-04-02 21:52:07 -06:00
|
|
|
/// Transfer lamports
|
2018-11-16 08:04:46 -08:00
|
|
|
/// * Transaction::keys[0] - source
|
|
|
|
/// * Transaction::keys[1] - destination
|
2019-04-02 21:52:07 -06:00
|
|
|
Transfer { lamports: u64 },
|
2018-11-16 08:04:46 -08:00
|
|
|
}
|
2019-02-28 04:48:44 -07:00
|
|
|
|
2019-04-03 09:45:57 -06:00
|
|
|
pub fn create_account(
|
2019-05-23 23:20:04 -07:00
|
|
|
from_pubkey: &Pubkey,
|
|
|
|
to_pubkey: &Pubkey,
|
2019-04-03 09:45:57 -06:00
|
|
|
lamports: u64,
|
|
|
|
space: u64,
|
|
|
|
program_id: &Pubkey,
|
|
|
|
) -> Instruction {
|
|
|
|
let account_metas = vec![
|
2019-05-23 23:20:04 -07:00
|
|
|
AccountMeta::new(*from_pubkey, true),
|
|
|
|
AccountMeta::new(*to_pubkey, false),
|
2019-04-03 09:45:57 -06:00
|
|
|
];
|
|
|
|
Instruction::new(
|
|
|
|
system_program::id(),
|
|
|
|
&SystemInstruction::CreateAccount {
|
|
|
|
lamports,
|
|
|
|
space,
|
|
|
|
program_id: *program_id,
|
|
|
|
},
|
|
|
|
account_metas,
|
|
|
|
)
|
|
|
|
}
|
2019-03-03 15:43:51 -07:00
|
|
|
|
2019-04-03 09:45:57 -06:00
|
|
|
/// Create and sign a transaction to create a system account
|
2019-05-23 23:20:04 -07:00
|
|
|
pub fn create_user_account(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
2019-04-03 09:45:57 -06:00
|
|
|
let program_id = system_program::id();
|
2019-05-23 23:20:04 -07:00
|
|
|
create_account(from_pubkey, to_pubkey, lamports, 0, &program_id)
|
2019-04-03 09:45:57 -06:00
|
|
|
}
|
2019-03-25 20:57:25 -06:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
pub fn assign(from_pubkey: &Pubkey, program_id: &Pubkey) -> Instruction {
|
|
|
|
let account_metas = vec![AccountMeta::new(*from_pubkey, true)];
|
2019-04-03 09:45:57 -06:00
|
|
|
Instruction::new(
|
|
|
|
system_program::id(),
|
|
|
|
&SystemInstruction::Assign {
|
|
|
|
program_id: *program_id,
|
|
|
|
},
|
|
|
|
account_metas,
|
|
|
|
)
|
|
|
|
}
|
2019-03-21 10:03:50 -06:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
2019-04-03 09:45:57 -06:00
|
|
|
let account_metas = vec![
|
2019-05-23 23:20:04 -07:00
|
|
|
AccountMeta::new(*from_pubkey, true),
|
2019-06-27 17:25:10 -04:00
|
|
|
AccountMeta::new_credit_only(*to_pubkey, false),
|
2019-04-03 09:45:57 -06:00
|
|
|
];
|
|
|
|
Instruction::new(
|
|
|
|
system_program::id(),
|
|
|
|
&SystemInstruction::Transfer { lamports },
|
|
|
|
account_metas,
|
|
|
|
)
|
|
|
|
}
|
2019-03-26 10:03:12 -06:00
|
|
|
|
2019-04-03 09:45:57 -06:00
|
|
|
/// Create and sign new SystemInstruction::Transfer transaction to many destinations
|
2019-05-23 23:20:04 -07:00
|
|
|
pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec<Instruction> {
|
2019-04-03 09:45:57 -06:00
|
|
|
to_lamports
|
|
|
|
.iter()
|
2019-05-23 23:20:04 -07:00
|
|
|
.map(|(to_pubkey, lamports)| transfer(from_pubkey, to_pubkey, *lamports))
|
2019-04-03 09:45:57 -06:00
|
|
|
.collect()
|
2019-03-26 10:03:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
fn get_keys(instruction: &Instruction) -> Vec<Pubkey> {
|
|
|
|
instruction.accounts.iter().map(|x| x.pubkey).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_move_many() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let alice_pubkey = Pubkey::new_rand();
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
let carol_pubkey = Pubkey::new_rand();
|
2019-03-26 10:03:12 -06:00
|
|
|
let to_lamports = vec![(bob_pubkey, 1), (carol_pubkey, 2)];
|
|
|
|
|
2019-04-03 09:45:57 -06:00
|
|
|
let instructions = transfer_many(&alice_pubkey, &to_lamports);
|
2019-03-26 10:03:12 -06:00
|
|
|
assert_eq!(instructions.len(), 2);
|
|
|
|
assert_eq!(get_keys(&instructions[0]), vec![alice_pubkey, bob_pubkey]);
|
|
|
|
assert_eq!(get_keys(&instructions[1]), vec![alice_pubkey, carol_pubkey]);
|
|
|
|
}
|
2019-02-28 04:48:44 -07:00
|
|
|
}
|