|
@@ -2,14 +2,18 @@
|
|
|
|
|
|
use bumpalo::Bump;
|
|
use bumpalo::Bump;
|
|
use safe_transmute::to_bytes::transmute_to_bytes;
|
|
use safe_transmute::to_bytes::transmute_to_bytes;
|
|
|
|
+use solana_program::account_info::next_account_info;
|
|
use solana_program::account_info::AccountInfo;
|
|
use solana_program::account_info::AccountInfo;
|
|
use solana_program::bpf_loader;
|
|
use solana_program::bpf_loader;
|
|
use solana_program::clock::Epoch;
|
|
use solana_program::clock::Epoch;
|
|
use solana_program::entrypoint::ProgramResult;
|
|
use solana_program::entrypoint::ProgramResult;
|
|
use solana_program::instruction::Instruction;
|
|
use solana_program::instruction::Instruction;
|
|
|
|
+use solana_program::program_error::ProgramError;
|
|
use solana_program::program_pack::Pack;
|
|
use solana_program::program_pack::Pack;
|
|
use solana_program::pubkey::Pubkey;
|
|
use solana_program::pubkey::Pubkey;
|
|
use solana_program::rent::Rent;
|
|
use solana_program::rent::Rent;
|
|
|
|
+use solana_program::system_instruction::SystemError;
|
|
|
|
+use solana_program::system_instruction::SystemInstruction;
|
|
use solana_program::system_program;
|
|
use solana_program::system_program;
|
|
use solana_program::sysvar::{self, Sysvar};
|
|
use solana_program::sysvar::{self, Sysvar};
|
|
use spl_token::state::Account as TokenAccount;
|
|
use spl_token::state::Account as TokenAccount;
|
|
@@ -18,6 +22,7 @@ use std::collections::HashMap;
|
|
use std::fmt::Debug;
|
|
use std::fmt::Debug;
|
|
use std::mem::size_of;
|
|
use std::mem::size_of;
|
|
use std::sync::{Arc, Mutex, MutexGuard};
|
|
use std::sync::{Arc, Mutex, MutexGuard};
|
|
|
|
+use thiserror::Error;
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
lazy_static::lazy_static! {
|
|
static ref ENV: Arc<Mutex<Environment>> = Arc::new(Mutex::new(Environment::new()));
|
|
static ref ENV: Arc<Mutex<Environment>> = Arc::new(Mutex::new(Environment::new()));
|
|
@@ -238,9 +243,120 @@ impl Program for SplToken {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Bare minimum implementation of the system program. Not all instructions are
|
|
|
|
+// implemented. PRs are welcome.
|
|
#[derive(Debug)]
|
|
#[derive(Debug)]
|
|
struct SystemProgram;
|
|
struct SystemProgram;
|
|
|
|
|
|
|
|
+impl SystemProgram {
|
|
|
|
+ fn create_account(
|
|
|
|
+ &self,
|
|
|
|
+ accounts: &[AccountInfo],
|
|
|
|
+ lamports: u64,
|
|
|
|
+ space: u64,
|
|
|
|
+ owner: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ let acc_infos = &mut accounts.into_iter();
|
|
|
|
+
|
|
|
|
+ let from = next_account_info(acc_infos)?;
|
|
|
|
+ let created = next_account_info(acc_infos)?;
|
|
|
|
+
|
|
|
|
+ if **created.lamports.borrow() > 0 {
|
|
|
|
+ return Err(ProgramError::Custom(
|
|
|
|
+ SystemError::AccountAlreadyInUse.to_u32(),
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ **from.lamports.borrow_mut() -= lamports;
|
|
|
|
+ **created.lamports.borrow_mut() += lamports;
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn transfer(&self, accounts: &[AccountInfo], lamports: u64) -> ProgramResult {
|
|
|
|
+ let acc_infos = &mut accounts.into_iter();
|
|
|
|
+
|
|
|
|
+ let from = next_account_info(acc_infos)?;
|
|
|
|
+ let to = next_account_info(acc_infos)?;
|
|
|
|
+
|
|
|
|
+ **from.lamports.borrow_mut() -= lamports;
|
|
|
|
+ **to.lamports.borrow_mut() += lamports;
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn create_account_with_seed(
|
|
|
|
+ &self,
|
|
|
|
+ accounts: &[AccountInfo],
|
|
|
|
+ base: Pubkey,
|
|
|
|
+ seed: String,
|
|
|
|
+ lamports: u64,
|
|
|
|
+ space: u64,
|
|
|
|
+ owner: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn assign(&self, _accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn advance_nonce_account(&self, _accounts: &[AccountInfo]) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn withdraw_nonce_account(&self, _accounts: &[AccountInfo], _lamports: u64) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn initialize_nonce_account(
|
|
|
|
+ &self,
|
|
|
|
+ _accounts: &[AccountInfo],
|
|
|
|
+ _entity: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn authorize_nonce_account(&self, _accounts: &[AccountInfo], _entity: Pubkey) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn allocate(&self, _accounts: &[AccountInfo], _space: u64) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn allocate_with_seed(
|
|
|
|
+ &self,
|
|
|
|
+ _accounts: &[AccountInfo],
|
|
|
|
+ _base: Pubkey,
|
|
|
|
+ _seed: String,
|
|
|
|
+ _space: u64,
|
|
|
|
+ _owner: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn assign_with_seed(
|
|
|
|
+ &self,
|
|
|
|
+ _accounts: &[AccountInfo],
|
|
|
|
+ _base: Pubkey,
|
|
|
|
+ _seed: String,
|
|
|
|
+ _owner: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn transfer_with_seed(
|
|
|
|
+ &self,
|
|
|
|
+ _accounts: &[AccountInfo],
|
|
|
|
+ _lamports: u64,
|
|
|
|
+ _from_seed: String,
|
|
|
|
+ _from_owner: Pubkey,
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ unimplemented!()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
impl Program for SystemProgram {
|
|
impl Program for SystemProgram {
|
|
fn entry(
|
|
fn entry(
|
|
&self,
|
|
&self,
|
|
@@ -248,8 +364,50 @@ impl Program for SystemProgram {
|
|
accounts: &[AccountInfo],
|
|
accounts: &[AccountInfo],
|
|
ix_data: &[u8],
|
|
ix_data: &[u8],
|
|
) -> ProgramResult {
|
|
) -> ProgramResult {
|
|
- // todo
|
|
|
|
- Ok(())
|
|
|
|
|
|
+ let ix: SystemInstruction =
|
|
|
|
+ bincode::deserialize(ix_data).map_err(|_| ProgramError::InvalidInstructionData)?;
|
|
|
|
+
|
|
|
|
+ match ix {
|
|
|
|
+ SystemInstruction::CreateAccount {
|
|
|
|
+ lamports,
|
|
|
|
+ space,
|
|
|
|
+ owner,
|
|
|
|
+ } => self.create_account(accounts, lamports, space, owner),
|
|
|
|
+ SystemInstruction::Transfer { lamports } => self.transfer(accounts, lamports),
|
|
|
|
+ SystemInstruction::CreateAccountWithSeed {
|
|
|
|
+ base,
|
|
|
|
+ seed,
|
|
|
|
+ lamports,
|
|
|
|
+ space,
|
|
|
|
+ owner,
|
|
|
|
+ } => self.create_account_with_seed(accounts, base, seed, lamports, space, owner),
|
|
|
|
+ SystemInstruction::Assign { owner } => self.assign(accounts, owner),
|
|
|
|
+ SystemInstruction::AdvanceNonceAccount => self.advance_nonce_account(accounts),
|
|
|
|
+ SystemInstruction::WithdrawNonceAccount(lamports) => {
|
|
|
|
+ self.withdraw_nonce_account(accounts, lamports)
|
|
|
|
+ }
|
|
|
|
+ SystemInstruction::InitializeNonceAccount(entity) => {
|
|
|
|
+ self.initialize_nonce_account(accounts, entity)
|
|
|
|
+ }
|
|
|
|
+ SystemInstruction::AuthorizeNonceAccount(entity) => {
|
|
|
|
+ self.authorize_nonce_account(accounts, entity)
|
|
|
|
+ }
|
|
|
|
+ SystemInstruction::Allocate { space } => self.allocate(accounts, space),
|
|
|
|
+ SystemInstruction::AllocateWithSeed {
|
|
|
|
+ base,
|
|
|
|
+ seed,
|
|
|
|
+ space,
|
|
|
|
+ owner,
|
|
|
|
+ } => self.allocate_with_seed(accounts, base, seed, space, owner),
|
|
|
|
+ SystemInstruction::AssignWithSeed { base, seed, owner } => {
|
|
|
|
+ self.assign_with_seed(accounts, base, seed, owner)
|
|
|
|
+ }
|
|
|
|
+ SystemInstruction::TransferWithSeed {
|
|
|
|
+ lamports,
|
|
|
|
+ from_seed,
|
|
|
|
+ from_owner,
|
|
|
|
+ } => self.transfer_with_seed(accounts, lamports, from_seed, from_owner),
|
|
|
|
+ }
|
|
}
|
|
}
|
|
fn id(&self) -> Pubkey {
|
|
fn id(&self) -> Pubkey {
|
|
system_program::ID
|
|
system_program::ID
|