Move system_program out of src/
This commit is contained in:
		
							
								
								
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1773,6 +1773,7 @@ dependencies = [
 | 
			
		||||
 "solana-metrics 0.11.0",
 | 
			
		||||
 "solana-noop 0.11.0",
 | 
			
		||||
 "solana-sdk 0.11.0",
 | 
			
		||||
 "solana-system-program 0.11.0",
 | 
			
		||||
 "solana-vote-signer 0.0.1",
 | 
			
		||||
 "sys-info 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
@@ -1955,6 +1956,17 @@ dependencies = [
 | 
			
		||||
 "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "solana-system-program"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "solana-sdk 0.11.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "solana-vote-signer"
 | 
			
		||||
version = "0.0.1"
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,7 @@ solana-lualoader = { path = "programs/native/lua_loader", version = "0.11.0" }
 | 
			
		||||
solana-metrics = { path = "metrics", version = "0.11.0" }
 | 
			
		||||
solana-noop = { path = "programs/native/noop", version = "0.11.0" }
 | 
			
		||||
solana-sdk = { path = "sdk", version = "0.11.0" }
 | 
			
		||||
solana-system-program = { path = "programs/native/system", version = "0.11.0" }
 | 
			
		||||
solana-vote-signer = { path = "vote-signer", version = "0.0.1" }
 | 
			
		||||
sys-info = "0.5.6"
 | 
			
		||||
tokio = "0.1"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ if [[ -n $CI ]]; then
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=2044 # Disable 'For loops over find output are fragile...'
 | 
			
		||||
for Cargo_toml in {sdk,metrics,drone,programs/native/{bpf_loader,lua_loader,noop},.}/Cargo.toml; do
 | 
			
		||||
for Cargo_toml in {sdk,metrics,drone,programs/native/{bpf_loader,lua_loader,noop,system_program},.}/Cargo.toml; do
 | 
			
		||||
  # TODO: Ensure the published version matches the contents of BUILDKITE_TAG
 | 
			
		||||
  (
 | 
			
		||||
    set -x
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,8 @@ use solana_sdk::hash::Hash;
 | 
			
		||||
use solana_sdk::packet::PACKET_DATA_SIZE;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::Keypair;
 | 
			
		||||
use solana_sdk::system_instruction::{SystemInstruction, SYSTEM_PROGRAM_ID};
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use solana_sdk::transaction::Transaction;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::io::{Error, ErrorKind};
 | 
			
		||||
@@ -143,7 +144,7 @@ impl Drone {
 | 
			
		||||
                    let mut transaction = Transaction::new(
 | 
			
		||||
                        &self.mint_keypair,
 | 
			
		||||
                        &[to],
 | 
			
		||||
                        Pubkey::new(&SYSTEM_PROGRAM_ID),
 | 
			
		||||
                        system_program::id(),
 | 
			
		||||
                        &create_instruction,
 | 
			
		||||
                        last_id,
 | 
			
		||||
                        0, /*fee*/
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ use bincode::deserialize;
 | 
			
		||||
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
 | 
			
		||||
use libc::c_char;
 | 
			
		||||
use solana_rbpf::EbpfVmRaw;
 | 
			
		||||
use solana_sdk::account::{Account, KeyedAccount};
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::loader_instruction::LoaderInstruction;
 | 
			
		||||
use solana_sdk::native_loader;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::io::prelude::*;
 | 
			
		||||
@@ -24,26 +24,6 @@ use std::io::{Error, ErrorKind};
 | 
			
		||||
use std::mem;
 | 
			
		||||
use std::sync::{Once, ONCE_INIT};
 | 
			
		||||
 | 
			
		||||
const BPF_LOADER_NAME: &str = "solana_bpf_loader";
 | 
			
		||||
const BPF_LOADER_PROGRAM_ID: [u8; 32] = [
 | 
			
		||||
    128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    0,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn id() -> Pubkey {
 | 
			
		||||
    Pubkey::new(&BPF_LOADER_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn account() -> Account {
 | 
			
		||||
    Account {
 | 
			
		||||
        tokens: 1,
 | 
			
		||||
        owner: id(),
 | 
			
		||||
        userdata: BPF_LOADER_NAME.as_bytes().to_vec(),
 | 
			
		||||
        executable: true,
 | 
			
		||||
        loader: native_loader::id(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO use rbpf's disassemble
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
fn dump_program(key: &Pubkey, prog: &[u8]) {
 | 
			
		||||
@@ -172,7 +152,7 @@ fn entrypoint(
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    tx_data: &[u8],
 | 
			
		||||
    tick_height: u64,
 | 
			
		||||
) -> bool {
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    static INIT: Once = ONCE_INIT;
 | 
			
		||||
    INIT.call_once(|| {
 | 
			
		||||
        // env_logger can only be initialized once
 | 
			
		||||
@@ -187,7 +167,7 @@ fn entrypoint(
 | 
			
		||||
            Ok(vm) => vm,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                warn!("create_vm failed: {}", e);
 | 
			
		||||
                return false;
 | 
			
		||||
                return Err(ProgramError::GenericError);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let mut v =
 | 
			
		||||
@@ -195,12 +175,12 @@ fn entrypoint(
 | 
			
		||||
        match vm.execute_program(v.as_mut_slice()) {
 | 
			
		||||
            Ok(status) => {
 | 
			
		||||
                if 0 == status {
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return Err(ProgramError::GenericError);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                warn!("execute_program failed: {}", e);
 | 
			
		||||
                return false;
 | 
			
		||||
                return Err(ProgramError::GenericError);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        deserialize_parameters(&mut keyed_accounts[1..], &v);
 | 
			
		||||
@@ -211,7 +191,7 @@ fn entrypoint(
 | 
			
		||||
    } else if let Ok(instruction) = deserialize(tx_data) {
 | 
			
		||||
        if keyed_accounts[0].signer_key().is_none() {
 | 
			
		||||
            warn!("key[0] did not sign the transaction");
 | 
			
		||||
            return false;
 | 
			
		||||
            return Err(ProgramError::GenericError);
 | 
			
		||||
        }
 | 
			
		||||
        match instruction {
 | 
			
		||||
            LoaderInstruction::Write { offset, bytes } => {
 | 
			
		||||
@@ -224,7 +204,7 @@ fn entrypoint(
 | 
			
		||||
                        keyed_accounts[0].account.userdata.len(),
 | 
			
		||||
                        offset + len
 | 
			
		||||
                    );
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return Err(ProgramError::GenericError);
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[0].account.userdata[offset..offset + len].copy_from_slice(&bytes);
 | 
			
		||||
            }
 | 
			
		||||
@@ -238,8 +218,9 @@ fn entrypoint(
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        warn!("Invalid program transaction: {:?}", tx_data);
 | 
			
		||||
        return Err(ProgramError::GenericError);
 | 
			
		||||
    }
 | 
			
		||||
    true
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -16,5 +16,5 @@ solana-sdk = { path = "../../../sdk", version = "0.11.0" }
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
name = "solana_erc20"
 | 
			
		||||
crate-type = ["lib", "cdylib"]
 | 
			
		||||
crate-type = ["cdylib"]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,49 +10,26 @@ extern crate serde_derive;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use solana_sdk::account::{Account, KeyedAccount};
 | 
			
		||||
use solana_sdk::native_loader;
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use std::sync::{Once, ONCE_INIT};
 | 
			
		||||
 | 
			
		||||
mod token_program;
 | 
			
		||||
 | 
			
		||||
const ERC20_NAME: &str = "solana_erc20";
 | 
			
		||||
const ERC20_PROGRAM_ID: [u8; 32] = [
 | 
			
		||||
    131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    0,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn id() -> Pubkey {
 | 
			
		||||
    Pubkey::new(&ERC20_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn account() -> Account {
 | 
			
		||||
    Account {
 | 
			
		||||
        tokens: 1,
 | 
			
		||||
        owner: id(),
 | 
			
		||||
        userdata: ERC20_NAME.as_bytes().to_vec(),
 | 
			
		||||
        executable: true,
 | 
			
		||||
        loader: native_loader::id(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
solana_entrypoint!(entrypoint);
 | 
			
		||||
fn entrypoint(
 | 
			
		||||
    program_id: &Pubkey,
 | 
			
		||||
    info: &mut [KeyedAccount],
 | 
			
		||||
    input: &[u8],
 | 
			
		||||
    _tick_height: u64,
 | 
			
		||||
) -> bool {
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    // env_logger can only be initialized once
 | 
			
		||||
    static INIT: Once = ONCE_INIT;
 | 
			
		||||
    INIT.call_once(env_logger::init);
 | 
			
		||||
 | 
			
		||||
    match token_program::TokenProgram::process(program_id, info, input) {
 | 
			
		||||
        Err(err) => {
 | 
			
		||||
            error!("error: {:?}", err);
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
        Ok(_) => true,
 | 
			
		||||
    }
 | 
			
		||||
    token_program::TokenProgram::process(program_id, info, input).map_err(|err| {
 | 
			
		||||
        error!("error: {:?}", err);
 | 
			
		||||
        ProgramError::GenericError
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,15 +7,16 @@ extern crate rlua;
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use bincode::deserialize;
 | 
			
		||||
use rlua::{Lua, Result, Table};
 | 
			
		||||
use rlua::{Lua, Table};
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::loader_instruction::LoaderInstruction;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use std::str;
 | 
			
		||||
use std::sync::{Once, ONCE_INIT};
 | 
			
		||||
 | 
			
		||||
/// Make KeyAccount values available to Lua.
 | 
			
		||||
fn set_accounts(lua: &Lua, name: &str, keyed_accounts: &[KeyedAccount]) -> Result<()> {
 | 
			
		||||
fn set_accounts(lua: &Lua, name: &str, keyed_accounts: &[KeyedAccount]) -> rlua::Result<()> {
 | 
			
		||||
    let accounts = lua.create_table()?;
 | 
			
		||||
    for (i, keyed_account) in keyed_accounts.iter().enumerate() {
 | 
			
		||||
        let account = lua.create_table()?;
 | 
			
		||||
@@ -37,7 +38,7 @@ fn set_accounts(lua: &Lua, name: &str, keyed_accounts: &[KeyedAccount]) -> Resul
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Commit the new KeyedAccount values.
 | 
			
		||||
fn update_accounts(lua: &Lua, name: &str, keyed_accounts: &mut [KeyedAccount]) -> Result<()> {
 | 
			
		||||
fn update_accounts(lua: &Lua, name: &str, keyed_accounts: &mut [KeyedAccount]) -> rlua::Result<()> {
 | 
			
		||||
    let globals = lua.globals();
 | 
			
		||||
    let accounts: Table = globals.get(name)?;
 | 
			
		||||
    for (i, keyed_account) in keyed_accounts.into_iter().enumerate() {
 | 
			
		||||
@@ -49,7 +50,7 @@ fn update_accounts(lua: &Lua, name: &str, keyed_accounts: &mut [KeyedAccount]) -
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn run_lua(keyed_accounts: &mut [KeyedAccount], code: &str, data: &[u8]) -> Result<()> {
 | 
			
		||||
fn run_lua(keyed_accounts: &mut [KeyedAccount], code: &str, data: &[u8]) -> rlua::Result<()> {
 | 
			
		||||
    let lua = Lua::new();
 | 
			
		||||
    let globals = lua.globals();
 | 
			
		||||
    let data_str = lua.create_string(data)?;
 | 
			
		||||
@@ -66,7 +67,7 @@ fn entrypoint(
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    tx_data: &[u8],
 | 
			
		||||
    _tick_height: u64,
 | 
			
		||||
) -> bool {
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    static INIT: Once = ONCE_INIT;
 | 
			
		||||
    INIT.call_once(|| {
 | 
			
		||||
        // env_logger can only be initialized once
 | 
			
		||||
@@ -79,17 +80,16 @@ fn entrypoint(
 | 
			
		||||
        match run_lua(&mut keyed_accounts[1..], &code, tx_data) {
 | 
			
		||||
            Ok(()) => {
 | 
			
		||||
                trace!("Lua success");
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                warn!("Lua Error: {:#?}", e);
 | 
			
		||||
                return false;
 | 
			
		||||
                return Err(ProgramError::GenericError);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if let Ok(instruction) = deserialize(tx_data) {
 | 
			
		||||
        if keyed_accounts[0].signer_key().is_none() {
 | 
			
		||||
            warn!("key[0] did not sign the transaction");
 | 
			
		||||
            return false;
 | 
			
		||||
            return Err(ProgramError::GenericError);
 | 
			
		||||
        }
 | 
			
		||||
        match instruction {
 | 
			
		||||
            LoaderInstruction::Write { offset, bytes } => {
 | 
			
		||||
@@ -102,7 +102,7 @@ fn entrypoint(
 | 
			
		||||
                        keyed_accounts[0].account.userdata.len(),
 | 
			
		||||
                        offset + len
 | 
			
		||||
                    );
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return Err(ProgramError::GenericError);
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[0].account.userdata[offset..offset + len].copy_from_slice(&bytes);
 | 
			
		||||
            }
 | 
			
		||||
@@ -117,9 +117,9 @@ fn entrypoint(
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        warn!("Invalid program transaction: {:?}", tx_data);
 | 
			
		||||
        return false;
 | 
			
		||||
        return Err(ProgramError::GenericError);
 | 
			
		||||
    }
 | 
			
		||||
    true
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
 | 
			
		||||
solana_entrypoint!(entrypoint);
 | 
			
		||||
@@ -10,10 +11,10 @@ fn entrypoint(
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    data: &[u8],
 | 
			
		||||
    tick_height: u64,
 | 
			
		||||
) -> bool {
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    println!("noop: program_id: {:?}", program_id);
 | 
			
		||||
    println!("noop: keyed_accounts: {:#?}", keyed_accounts);
 | 
			
		||||
    println!("noop: data: {:?}", data);
 | 
			
		||||
    println!("noop: tick_height: {:?}", tick_height);
 | 
			
		||||
    true
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								programs/native/system/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								programs/native/system/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "solana-system-program"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
description = "Solana system program"
 | 
			
		||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
 | 
			
		||||
repository = "https://github.com/solana-labs/solana"
 | 
			
		||||
license = "Apache-2.0"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
bincode = "1.0.0"
 | 
			
		||||
env_logger = "0.6.0"
 | 
			
		||||
log = "0.4.2"
 | 
			
		||||
serde = "1.0.27"
 | 
			
		||||
solana-sdk = { path = "../../../sdk", version = "0.11.0" }
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
name = "solana_system_program"
 | 
			
		||||
crate-type = ["cdylib"]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										112
									
								
								programs/native/system/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								programs/native/system/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
extern crate bincode;
 | 
			
		||||
extern crate env_logger;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate log;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use bincode::deserialize;
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use std::sync::{Once, ONCE_INIT};
 | 
			
		||||
 | 
			
		||||
solana_entrypoint!(entrypoint);
 | 
			
		||||
fn entrypoint(
 | 
			
		||||
    _program_id: &Pubkey,
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    data: &[u8],
 | 
			
		||||
    _tick_height: u64,
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    static INIT: Once = ONCE_INIT;
 | 
			
		||||
    INIT.call_once(|| {
 | 
			
		||||
        // env_logger can only be initialized once
 | 
			
		||||
        env_logger::init();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if let Ok(syscall) = deserialize(data) {
 | 
			
		||||
        trace!("process_instruction: {:?}", syscall);
 | 
			
		||||
        trace!("keyed_accounts: {:?}", keyed_accounts);
 | 
			
		||||
        let from = 0;
 | 
			
		||||
 | 
			
		||||
        // all system instructions require that accounts_keys[0] be a signer
 | 
			
		||||
        if keyed_accounts[from].signer_key().is_none() {
 | 
			
		||||
            info!("account[from] is unsigned");
 | 
			
		||||
            Err(ProgramError::InvalidArgument)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        match syscall {
 | 
			
		||||
            SystemInstruction::CreateAccount {
 | 
			
		||||
                tokens,
 | 
			
		||||
                space,
 | 
			
		||||
                program_id,
 | 
			
		||||
            } => {
 | 
			
		||||
                let to = 1;
 | 
			
		||||
                if !system_program::check_id(&keyed_accounts[from].account.owner) {
 | 
			
		||||
                    info!("CreateAccount: invalid account[from] owner");
 | 
			
		||||
                    Err(ProgramError::InvalidArgument)?;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if space > 0
 | 
			
		||||
                    && (!keyed_accounts[to].account.userdata.is_empty()
 | 
			
		||||
                        || !system_program::check_id(&keyed_accounts[to].account.owner))
 | 
			
		||||
                {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "CreateAccount: invalid argument space: {} accounts.userdata.len(): {}",
 | 
			
		||||
                        space,
 | 
			
		||||
                        keyed_accounts[to].account.userdata.len(),
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(ProgramError::InvalidArgument)?;
 | 
			
		||||
                }
 | 
			
		||||
                if tokens > keyed_accounts[from].account.tokens {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "CreateAccount: insufficient tokens ({}, need {})",
 | 
			
		||||
                        keyed_accounts[from].account.tokens, tokens
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(ProgramError::ResultWithNegativeTokens)?;
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[from].account.tokens -= tokens;
 | 
			
		||||
                keyed_accounts[to].account.tokens += tokens;
 | 
			
		||||
                keyed_accounts[to].account.owner = program_id;
 | 
			
		||||
                keyed_accounts[to].account.userdata = vec![0; space as usize];
 | 
			
		||||
                keyed_accounts[to].account.executable = false;
 | 
			
		||||
                keyed_accounts[to].account.loader = Pubkey::default();
 | 
			
		||||
            }
 | 
			
		||||
            SystemInstruction::Assign { program_id } => {
 | 
			
		||||
                if !system_program::check_id(&keyed_accounts[from].account.owner) {
 | 
			
		||||
                    Err(ProgramError::AssignOfUnownedAccount)?;
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[from].account.owner = program_id;
 | 
			
		||||
            }
 | 
			
		||||
            SystemInstruction::Move { tokens } => {
 | 
			
		||||
                let to = 1;
 | 
			
		||||
 | 
			
		||||
                // bank should be verifying correctness
 | 
			
		||||
                if tokens > keyed_accounts[from].account.tokens {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "Move: insufficient tokens ({}, need {})",
 | 
			
		||||
                        keyed_accounts[from].account.tokens, tokens
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(ProgramError::ResultWithNegativeTokens)?;
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[from].account.tokens -= tokens;
 | 
			
		||||
                keyed_accounts[to].account.tokens += tokens;
 | 
			
		||||
            }
 | 
			
		||||
            SystemInstruction::Spawn => {
 | 
			
		||||
                if !keyed_accounts[from].account.executable
 | 
			
		||||
                    || keyed_accounts[from].account.loader != Pubkey::default()
 | 
			
		||||
                {
 | 
			
		||||
                    Err(ProgramError::AccountNotFinalized)?;
 | 
			
		||||
                }
 | 
			
		||||
                keyed_accounts[from].account.loader = keyed_accounts[from].account.owner;
 | 
			
		||||
                keyed_accounts[from].account.owner = *keyed_accounts[from].signer_key().unwrap();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    } else {
 | 
			
		||||
        info!("Invalid transaction instruction userdata: {:?}", data);
 | 
			
		||||
        Err(ProgramError::InvalidArgument)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								sdk/src/bpf_loader.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								sdk/src/bpf_loader.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
use pubkey::Pubkey;
 | 
			
		||||
 | 
			
		||||
pub const BPF_LOADER_PROGRAM_ID: [u8; 32] = [
 | 
			
		||||
    128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    0,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub fn id() -> Pubkey {
 | 
			
		||||
    Pubkey::new(&BPF_LOADER_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
pub mod account;
 | 
			
		||||
pub mod bpf_loader;
 | 
			
		||||
pub mod hash;
 | 
			
		||||
pub mod loader_instruction;
 | 
			
		||||
pub mod native_loader;
 | 
			
		||||
@@ -7,6 +8,7 @@ pub mod packet;
 | 
			
		||||
pub mod pubkey;
 | 
			
		||||
pub mod signature;
 | 
			
		||||
pub mod system_instruction;
 | 
			
		||||
pub mod system_program;
 | 
			
		||||
pub mod timing;
 | 
			
		||||
pub mod transaction;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,44 @@
 | 
			
		||||
use account::KeyedAccount;
 | 
			
		||||
use pubkey::Pubkey;
 | 
			
		||||
use std;
 | 
			
		||||
 | 
			
		||||
/// Reasons a program might have rejected an instruction.
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Clone)]
 | 
			
		||||
pub enum ProgramError {
 | 
			
		||||
    /// The program instruction returned an error
 | 
			
		||||
    GenericError,
 | 
			
		||||
 | 
			
		||||
    /// The arguments provided to a program instruction where invalid
 | 
			
		||||
    InvalidArgument,
 | 
			
		||||
 | 
			
		||||
    /// An instruction resulted in an account with a negative balance
 | 
			
		||||
    /// The difference from InsufficientFundsForFee is that the transaction was executed by the
 | 
			
		||||
    /// contract
 | 
			
		||||
    ResultWithNegativeTokens,
 | 
			
		||||
 | 
			
		||||
    /// Program's instruction token balance does not equal the balance after the instruction
 | 
			
		||||
    UnbalancedInstruction,
 | 
			
		||||
 | 
			
		||||
    /// Program modified an account's program id
 | 
			
		||||
    ModifiedProgramId,
 | 
			
		||||
 | 
			
		||||
    /// Program spent the tokens of an account that doesn't belong to it
 | 
			
		||||
    ExternalAccountTokenSpend,
 | 
			
		||||
 | 
			
		||||
    /// SystemInstruction::Assign was attempted on an account unowned by the system program
 | 
			
		||||
    AssignOfUnownedAccount,
 | 
			
		||||
 | 
			
		||||
    /// SystemInstruction::Spawn was attempted on an account that was not finalized by
 | 
			
		||||
    /// LoaderInstruction::Finalize
 | 
			
		||||
    AccountNotFinalized,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl std::fmt::Display for ProgramError {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
			
		||||
        write!(f, "error")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl std::error::Error for ProgramError {}
 | 
			
		||||
 | 
			
		||||
// All native programs export a symbol named process()
 | 
			
		||||
pub const ENTRYPOINT: &str = "process";
 | 
			
		||||
@@ -10,7 +49,7 @@ pub type Entrypoint = unsafe extern "C" fn(
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    data: &[u8],
 | 
			
		||||
    tick_height: u64,
 | 
			
		||||
) -> bool;
 | 
			
		||||
) -> Result<(), ProgramError>;
 | 
			
		||||
 | 
			
		||||
// Convenience macro to define the native program entrypoint.  Supply a fn to this macro that
 | 
			
		||||
// conforms to the `Entrypoint` type signature.
 | 
			
		||||
@@ -23,29 +62,8 @@ macro_rules! solana_entrypoint(
 | 
			
		||||
            keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
            data: &[u8],
 | 
			
		||||
            tick_height: u64
 | 
			
		||||
        ) -> bool {
 | 
			
		||||
            return $entrypoint(program_id, keyed_accounts, data, tick_height);
 | 
			
		||||
        ) -> Result<(), ProgramError> {
 | 
			
		||||
            $entrypoint(program_id, keyed_accounts, data, tick_height)
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/// Reasons a program might have rejected an instruction.
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Clone)]
 | 
			
		||||
pub enum ProgramError {
 | 
			
		||||
    /// Contract's transactions resulted in an account with a negative balance
 | 
			
		||||
    /// The difference from InsufficientFundsForFee is that the transaction was executed by the
 | 
			
		||||
    /// contract
 | 
			
		||||
    ResultWithNegativeTokens,
 | 
			
		||||
 | 
			
		||||
    /// The program returned an error
 | 
			
		||||
    GenericError,
 | 
			
		||||
 | 
			
		||||
    /// Program's instruction token balance does not equal the balance after the instruction
 | 
			
		||||
    UnbalancedInstruction,
 | 
			
		||||
 | 
			
		||||
    /// Program modified an account's program id
 | 
			
		||||
    ModifiedProgramId,
 | 
			
		||||
 | 
			
		||||
    /// Program spent the tokens of an account that doesn't belong to it
 | 
			
		||||
    ExternalAccountTokenSpend,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
use pubkey::Pubkey;
 | 
			
		||||
 | 
			
		||||
pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32];
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
			
		||||
pub enum SystemInstruction {
 | 
			
		||||
    /// Create a new account
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								sdk/src/system_program.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								sdk/src/system_program.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
use pubkey::Pubkey;
 | 
			
		||||
 | 
			
		||||
pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32];
 | 
			
		||||
 | 
			
		||||
pub fn id() -> Pubkey {
 | 
			
		||||
    Pubkey::new(&SYSTEM_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn check_id(program_id: &Pubkey) -> bool {
 | 
			
		||||
    program_id.as_ref() == SYSTEM_PROGRAM_ID
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								src/bank.rs
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/bank.rs
									
									
									
									
									
								
							@@ -21,14 +21,15 @@ use poh_service::NUM_TICKS_PER_SECOND;
 | 
			
		||||
use rayon::prelude::*;
 | 
			
		||||
use rpc::RpcSignatureStatus;
 | 
			
		||||
use runtime::{self, RuntimeError};
 | 
			
		||||
use solana_erc20;
 | 
			
		||||
use solana_sdk::account::Account;
 | 
			
		||||
use solana_sdk::bpf_loader;
 | 
			
		||||
use solana_sdk::hash::{hash, Hash};
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::Keypair;
 | 
			
		||||
use solana_sdk::signature::Signature;
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use solana_sdk::timing::{duration_as_us, timestamp};
 | 
			
		||||
use solana_sdk::transaction::Transaction;
 | 
			
		||||
use std;
 | 
			
		||||
@@ -37,7 +38,6 @@ use std::result;
 | 
			
		||||
use std::sync::atomic::{AtomicUsize, Ordering};
 | 
			
		||||
use std::sync::{Arc, Mutex, RwLock};
 | 
			
		||||
use std::time::Instant;
 | 
			
		||||
use system_program;
 | 
			
		||||
use system_transaction::SystemTransaction;
 | 
			
		||||
use tokio::prelude::Future;
 | 
			
		||||
 | 
			
		||||
@@ -397,14 +397,44 @@ impl Bank {
 | 
			
		||||
        bank
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_builtin_programs(&self) {
 | 
			
		||||
    fn add_system_program(&self) {
 | 
			
		||||
        let mut accounts = self.accounts.write().unwrap();
 | 
			
		||||
 | 
			
		||||
        // Preload Bpf Loader account
 | 
			
		||||
        accounts.store(&solana_bpf_loader::id(), &solana_bpf_loader::account());
 | 
			
		||||
        let system_program_account = Account {
 | 
			
		||||
            tokens: 1,
 | 
			
		||||
            owner: system_program::id(),
 | 
			
		||||
            userdata: b"solana_system_program".to_vec(),
 | 
			
		||||
            executable: true,
 | 
			
		||||
            loader: native_loader::id(),
 | 
			
		||||
        };
 | 
			
		||||
        accounts.store(&system_program::id(), &system_program_account);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Preload Erc20 token program
 | 
			
		||||
        accounts.store(&solana_erc20::id(), &solana_erc20::account());
 | 
			
		||||
    fn add_builtin_programs(&self) {
 | 
			
		||||
        self.add_system_program();
 | 
			
		||||
        let mut accounts = self.accounts.write().unwrap();
 | 
			
		||||
 | 
			
		||||
        // Bpf Loader
 | 
			
		||||
        let bpf_loader_account = Account {
 | 
			
		||||
            tokens: 1,
 | 
			
		||||
            owner: bpf_loader::id(),
 | 
			
		||||
            userdata: b"solana_bpf_loader".to_vec(),
 | 
			
		||||
            executable: true,
 | 
			
		||||
            loader: native_loader::id(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        accounts.store(&bpf_loader::id(), &bpf_loader_account);
 | 
			
		||||
 | 
			
		||||
        // Erc20 token program
 | 
			
		||||
        let erc20_account = Account {
 | 
			
		||||
            tokens: 1,
 | 
			
		||||
            owner: runtime::erc20_id(),
 | 
			
		||||
            userdata: b"solana_erc20".to_vec(),
 | 
			
		||||
            executable: true,
 | 
			
		||||
            loader: native_loader::id(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        accounts.store(&runtime::erc20_id(), &erc20_account);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return the last entry ID registered.
 | 
			
		||||
@@ -1175,9 +1205,7 @@ impl Bank {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn read_balance(account: &Account) -> u64 {
 | 
			
		||||
        if system_program::check_id(&account.owner) {
 | 
			
		||||
            system_program::get_balance(account)
 | 
			
		||||
        } else if budget_program::check_id(&account.owner) {
 | 
			
		||||
        if budget_program::check_id(&account.owner) {
 | 
			
		||||
            budget_program::get_balance(account)
 | 
			
		||||
        } else {
 | 
			
		||||
            account.tokens
 | 
			
		||||
@@ -1812,6 +1840,7 @@ mod tests {
 | 
			
		||||
    fn test_process_ledger_simple() {
 | 
			
		||||
        let (ledger, pubkey) = create_sample_ledger(1);
 | 
			
		||||
        let bank = Bank::default();
 | 
			
		||||
        bank.add_system_program();
 | 
			
		||||
        let (ledger_height, last_id) = bank.process_ledger(ledger).unwrap();
 | 
			
		||||
        assert_eq!(bank.get_balance(&pubkey), 1);
 | 
			
		||||
        assert_eq!(ledger_height, 5);
 | 
			
		||||
@@ -1832,8 +1861,10 @@ mod tests {
 | 
			
		||||
        let ledger1 = create_sample_ledger_with_mint_and_keypairs(&mint, &keypairs);
 | 
			
		||||
 | 
			
		||||
        let bank0 = Bank::default();
 | 
			
		||||
        bank0.add_system_program();
 | 
			
		||||
        bank0.process_ledger(ledger0).unwrap();
 | 
			
		||||
        let bank1 = Bank::default();
 | 
			
		||||
        bank1.add_system_program();
 | 
			
		||||
        bank1.process_ledger(ledger1).unwrap();
 | 
			
		||||
 | 
			
		||||
        let initial_state = bank0.hash_internal_state();
 | 
			
		||||
@@ -2127,7 +2158,7 @@ mod tests {
 | 
			
		||||
            130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
            0, 0, 0, 0,
 | 
			
		||||
        ]);
 | 
			
		||||
        let token = Pubkey::new(&[
 | 
			
		||||
        let erc20 = Pubkey::new(&[
 | 
			
		||||
            131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
            0, 0, 0, 0,
 | 
			
		||||
        ]);
 | 
			
		||||
@@ -2138,10 +2169,10 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        assert_eq!(system_program::id(), system);
 | 
			
		||||
        assert_eq!(native_loader::id(), native);
 | 
			
		||||
        assert_eq!(solana_bpf_loader::id(), bpf);
 | 
			
		||||
        assert_eq!(bpf_loader::id(), bpf);
 | 
			
		||||
        assert_eq!(budget_program::id(), budget);
 | 
			
		||||
        assert_eq!(storage_program::id(), storage);
 | 
			
		||||
        assert_eq!(solana_erc20::id(), token);
 | 
			
		||||
        assert_eq!(runtime::erc20_id(), erc20);
 | 
			
		||||
        assert_eq!(vote_program::id(), vote);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2151,10 +2182,10 @@ mod tests {
 | 
			
		||||
        let ids = vec![
 | 
			
		||||
            system_program::id(),
 | 
			
		||||
            native_loader::id(),
 | 
			
		||||
            solana_bpf_loader::id(),
 | 
			
		||||
            bpf_loader::id(),
 | 
			
		||||
            budget_program::id(),
 | 
			
		||||
            storage_program::id(),
 | 
			
		||||
            solana_erc20::id(),
 | 
			
		||||
            runtime::erc20_id(),
 | 
			
		||||
            vote_program::id(),
 | 
			
		||||
        ];
 | 
			
		||||
        assert!(ids.into_iter().all(move |id| unique.insert(id)));
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,9 @@ use payment_plan::Payment;
 | 
			
		||||
use solana_sdk::hash::Hash;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::{Keypair, KeypairUtil};
 | 
			
		||||
use solana_sdk::system_instruction::{SystemInstruction, SYSTEM_PROGRAM_ID};
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
 | 
			
		||||
use solana_sdk::transaction::{self, Transaction};
 | 
			
		||||
 | 
			
		||||
pub trait BudgetTransaction {
 | 
			
		||||
@@ -85,7 +87,7 @@ impl BudgetTransaction for Transaction {
 | 
			
		||||
        };
 | 
			
		||||
        let budget_instruction = Instruction::NewBudget(BudgetExpr::Pay(payment));
 | 
			
		||||
 | 
			
		||||
        let program_ids = vec![Pubkey::new(&SYSTEM_PROGRAM_ID), budget_program::id()];
 | 
			
		||||
        let program_ids = vec![system_program::id(), budget_program::id()];
 | 
			
		||||
 | 
			
		||||
        let instructions = vec![
 | 
			
		||||
            transaction::Instruction::new(0, &system_instruction, vec![0, 1]),
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,6 @@ pub mod storage_stage;
 | 
			
		||||
pub mod storage_transaction;
 | 
			
		||||
pub mod store_ledger_stage;
 | 
			
		||||
pub mod streamer;
 | 
			
		||||
pub mod system_program;
 | 
			
		||||
pub mod system_transaction;
 | 
			
		||||
pub mod thin_client;
 | 
			
		||||
pub mod tpu;
 | 
			
		||||
@@ -125,8 +124,6 @@ extern crate solana_jsonrpc_core as jsonrpc_core;
 | 
			
		||||
extern crate solana_jsonrpc_http_server as jsonrpc_http_server;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate solana_jsonrpc_macros as jsonrpc_macros;
 | 
			
		||||
extern crate solana_bpf_loader;
 | 
			
		||||
extern crate solana_erc20;
 | 
			
		||||
extern crate solana_jsonrpc_pubsub as jsonrpc_pubsub;
 | 
			
		||||
extern crate solana_jsonrpc_ws_server as jsonrpc_ws_server;
 | 
			
		||||
extern crate solana_metrics;
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ mod tests {
 | 
			
		||||
    use bincode::deserialize;
 | 
			
		||||
    use ledger::Block;
 | 
			
		||||
    use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
    use system_program;
 | 
			
		||||
    use solana_sdk::system_program;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_transactions() {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::loader_instruction::LoaderInstruction;
 | 
			
		||||
pub use solana_sdk::native_loader::*;
 | 
			
		||||
use solana_sdk::native_program;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
@@ -51,7 +52,7 @@ pub fn process_instruction(
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
    ix_userdata: &[u8],
 | 
			
		||||
    tick_height: u64,
 | 
			
		||||
) -> bool {
 | 
			
		||||
) -> Result<(), ProgramError> {
 | 
			
		||||
    if keyed_accounts[0].account.executable {
 | 
			
		||||
        // dispatch it
 | 
			
		||||
        let name = keyed_accounts[0].account.userdata.clone();
 | 
			
		||||
@@ -59,7 +60,7 @@ pub fn process_instruction(
 | 
			
		||||
            Ok(v) => v,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                warn!("Invalid UTF-8 sequence: {}", e);
 | 
			
		||||
                return false;
 | 
			
		||||
                return Err(ProgramError::GenericError);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        trace!("Call native {:?}", name);
 | 
			
		||||
@@ -76,7 +77,7 @@ pub fn process_instruction(
 | 
			
		||||
                                e,
 | 
			
		||||
                                native_program::ENTRYPOINT
 | 
			
		||||
                            );
 | 
			
		||||
                            return false;
 | 
			
		||||
                            return Err(ProgramError::GenericError);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                return entrypoint(
 | 
			
		||||
@@ -88,13 +89,13 @@ pub fn process_instruction(
 | 
			
		||||
            },
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                warn!("Unable to load: {:?}", e);
 | 
			
		||||
                return false;
 | 
			
		||||
                return Err(ProgramError::GenericError);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if let Ok(instruction) = deserialize(ix_userdata) {
 | 
			
		||||
        if keyed_accounts[0].signer_key().is_none() {
 | 
			
		||||
            warn!("key[0] did not sign the transaction");
 | 
			
		||||
            return false;
 | 
			
		||||
            return Err(ProgramError::GenericError);
 | 
			
		||||
        }
 | 
			
		||||
        match instruction {
 | 
			
		||||
            LoaderInstruction::Write { offset, bytes } => {
 | 
			
		||||
@@ -106,7 +107,7 @@ pub fn process_instruction(
 | 
			
		||||
                        keyed_accounts[0].account.userdata.len(),
 | 
			
		||||
                        offset + bytes.len()
 | 
			
		||||
                    );
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return Err(ProgramError::GenericError);
 | 
			
		||||
                }
 | 
			
		||||
                // native loader takes a name and we assume it all comes in at once
 | 
			
		||||
                keyed_accounts[0].account.userdata = bytes;
 | 
			
		||||
@@ -122,6 +123,7 @@ pub fn process_instruction(
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        warn!("Invalid userdata in instruction: {:?}", ix_userdata);
 | 
			
		||||
        return Err(ProgramError::GenericError);
 | 
			
		||||
    }
 | 
			
		||||
    true
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@ use native_loader;
 | 
			
		||||
use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount};
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use solana_sdk::transaction::Transaction;
 | 
			
		||||
use storage_program;
 | 
			
		||||
use system_program;
 | 
			
		||||
use vote_program;
 | 
			
		||||
 | 
			
		||||
/// Reasons the runtime might have rejected a transaction.
 | 
			
		||||
@@ -16,12 +16,21 @@ pub enum RuntimeError {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn is_legacy_program(program_id: &Pubkey) -> bool {
 | 
			
		||||
    system_program::check_id(program_id)
 | 
			
		||||
        || budget_program::check_id(program_id)
 | 
			
		||||
    budget_program::check_id(program_id)
 | 
			
		||||
        || storage_program::check_id(program_id)
 | 
			
		||||
        || vote_program::check_id(program_id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Rename and find a better home for this in the sdk/
 | 
			
		||||
pub fn erc20_id() -> Pubkey {
 | 
			
		||||
    const ERC20_PROGRAM_ID: [u8; 32] = [
 | 
			
		||||
        131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
        0, 0,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    Pubkey::new(&ERC20_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Process an instruction
 | 
			
		||||
/// This method calls the instruction's program entrypoint method
 | 
			
		||||
fn process_instruction(
 | 
			
		||||
@@ -36,9 +45,7 @@ fn process_instruction(
 | 
			
		||||
    // Call the program method
 | 
			
		||||
    // It's up to the program to implement its own rules on moving funds
 | 
			
		||||
    if is_legacy_program(&program_id) {
 | 
			
		||||
        if system_program::check_id(&program_id) {
 | 
			
		||||
            system_program::process(&tx, instruction_index, program_accounts)?;
 | 
			
		||||
        } else if budget_program::check_id(&program_id) {
 | 
			
		||||
        if budget_program::check_id(&program_id) {
 | 
			
		||||
            budget_program::process(&tx, instruction_index, program_accounts)?;
 | 
			
		||||
        } else if storage_program::check_id(&program_id) {
 | 
			
		||||
            storage_program::process(&tx, instruction_index, program_accounts)?;
 | 
			
		||||
@@ -47,6 +54,7 @@ fn process_instruction(
 | 
			
		||||
        } else {
 | 
			
		||||
            unreachable!();
 | 
			
		||||
        };
 | 
			
		||||
        Ok(())
 | 
			
		||||
    } else {
 | 
			
		||||
        let mut keyed_accounts = create_keyed_accounts(executable_accounts);
 | 
			
		||||
        let mut keyed_accounts2: Vec<_> = tx.instructions[instruction_index]
 | 
			
		||||
@@ -61,16 +69,13 @@ fn process_instruction(
 | 
			
		||||
            .collect();
 | 
			
		||||
        keyed_accounts.append(&mut keyed_accounts2);
 | 
			
		||||
 | 
			
		||||
        if !native_loader::process_instruction(
 | 
			
		||||
        native_loader::process_instruction(
 | 
			
		||||
            &program_id,
 | 
			
		||||
            &mut keyed_accounts,
 | 
			
		||||
            &tx.instructions[instruction_index].userdata,
 | 
			
		||||
            tick_height,
 | 
			
		||||
        ) {
 | 
			
		||||
            return Err(ProgramError::GenericError);
 | 
			
		||||
        }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn verify_instruction(
 | 
			
		||||
 
 | 
			
		||||
@@ -329,8 +329,8 @@ mod tests {
 | 
			
		||||
    use solana_sdk::hash::Hash;
 | 
			
		||||
    use solana_sdk::signature::{Keypair, KeypairUtil};
 | 
			
		||||
    use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
    use solana_sdk::system_program;
 | 
			
		||||
    use solana_sdk::transaction::{Instruction, Transaction};
 | 
			
		||||
    use system_program;
 | 
			
		||||
    use system_transaction::{memfind, test_tx};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,418 +0,0 @@
 | 
			
		||||
//! system program
 | 
			
		||||
 | 
			
		||||
use bincode::deserialize;
 | 
			
		||||
use solana_sdk::account::Account;
 | 
			
		||||
use solana_sdk::native_program::ProgramError;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::system_instruction::{SystemInstruction, SYSTEM_PROGRAM_ID};
 | 
			
		||||
use solana_sdk::transaction::Transaction;
 | 
			
		||||
use std;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    InvalidArgument,
 | 
			
		||||
    AssignOfUnownedAccount,
 | 
			
		||||
    AccountNotFinalized,
 | 
			
		||||
    ResultWithNegativeTokens,
 | 
			
		||||
}
 | 
			
		||||
impl std::fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
			
		||||
        write!(f, "error")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl std::error::Error for Error {}
 | 
			
		||||
 | 
			
		||||
pub type Result<T> = std::result::Result<T, Error>;
 | 
			
		||||
 | 
			
		||||
pub fn check_id(program_id: &Pubkey) -> bool {
 | 
			
		||||
    program_id.as_ref() == SYSTEM_PROGRAM_ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn id() -> Pubkey {
 | 
			
		||||
    Pubkey::new(&SYSTEM_PROGRAM_ID)
 | 
			
		||||
}
 | 
			
		||||
pub fn get_balance(account: &Account) -> u64 {
 | 
			
		||||
    account.tokens
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.signer_key(pix, from).is_none() {
 | 
			
		||||
            Err(Error::InvalidArgument)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        match syscall {
 | 
			
		||||
            SystemInstruction::CreateAccount {
 | 
			
		||||
                tokens,
 | 
			
		||||
                space,
 | 
			
		||||
                program_id,
 | 
			
		||||
            } => {
 | 
			
		||||
                let to = 1;
 | 
			
		||||
 | 
			
		||||
                if !check_id(&accounts[from].owner) {
 | 
			
		||||
                    info!("CreateAccount: invalid account[from] owner");
 | 
			
		||||
                    Err(Error::InvalidArgument)?;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if space > 0
 | 
			
		||||
                    && (!accounts[to].userdata.is_empty() || !check_id(&accounts[to].owner))
 | 
			
		||||
                {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "CreateAccount: invalid argument space: {} accounts.userdata.len(): {}",
 | 
			
		||||
                        space,
 | 
			
		||||
                        accounts[to].userdata.len(),
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(Error::InvalidArgument)?;
 | 
			
		||||
                }
 | 
			
		||||
                if tokens > accounts[from].tokens {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "CreateAccount: insufficient tokens ({}, need {})",
 | 
			
		||||
                        accounts[from].tokens, tokens
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(Error::ResultWithNegativeTokens)?;
 | 
			
		||||
                }
 | 
			
		||||
                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[from].owner) {
 | 
			
		||||
                    Err(Error::AssignOfUnownedAccount)?;
 | 
			
		||||
                }
 | 
			
		||||
                accounts[from].owner = program_id;
 | 
			
		||||
            }
 | 
			
		||||
            SystemInstruction::Move { tokens } => {
 | 
			
		||||
                let to = 1;
 | 
			
		||||
 | 
			
		||||
                //bank should be verifying correctness
 | 
			
		||||
                if tokens > accounts[from].tokens {
 | 
			
		||||
                    info!(
 | 
			
		||||
                        "Move: insufficient tokens ({}, need {})",
 | 
			
		||||
                        accounts[from].tokens, tokens
 | 
			
		||||
                    );
 | 
			
		||||
                    Err(Error::ResultWithNegativeTokens)?;
 | 
			
		||||
                }
 | 
			
		||||
                accounts[from].tokens -= tokens;
 | 
			
		||||
                accounts[to].tokens += tokens;
 | 
			
		||||
            }
 | 
			
		||||
            SystemInstruction::Spawn => {
 | 
			
		||||
                if !accounts[from].executable || accounts[from].loader != Pubkey::default() {
 | 
			
		||||
                    Err(Error::AccountNotFinalized)?;
 | 
			
		||||
                }
 | 
			
		||||
                accounts[from].loader = accounts[from].owner;
 | 
			
		||||
                accounts[from].owner = tx.account_keys[from];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    } else {
 | 
			
		||||
        info!("Invalid transaction userdata: {:?}", tx.userdata(pix));
 | 
			
		||||
        Err(Error::InvalidArgument)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn process(
 | 
			
		||||
    tx: &Transaction,
 | 
			
		||||
    instruction_index: usize,
 | 
			
		||||
    accounts: &mut [&mut Account],
 | 
			
		||||
) -> std::result::Result<(), ProgramError> {
 | 
			
		||||
    process_instruction(&tx, instruction_index, accounts).map_err(|err| match err {
 | 
			
		||||
        Error::ResultWithNegativeTokens => ProgramError::ResultWithNegativeTokens,
 | 
			
		||||
        _ => ProgramError::GenericError,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use solana_sdk::account::Account;
 | 
			
		||||
    use solana_sdk::hash::Hash;
 | 
			
		||||
    use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
    use solana_sdk::signature::{Keypair, KeypairUtil};
 | 
			
		||||
    use solana_sdk::transaction::Instruction;
 | 
			
		||||
    use system_transaction::SystemTransaction;
 | 
			
		||||
 | 
			
		||||
    /// 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<()> {
 | 
			
		||||
        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]
 | 
			
		||||
    fn test_create_noop() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        let tx = Transaction::system_new(&from, to.pubkey(), 0, Hash::default());
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert_eq!(accounts[0].tokens, 0);
 | 
			
		||||
        assert_eq!(accounts[1].tokens, 0);
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_spend() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].tokens = 1;
 | 
			
		||||
        let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default());
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert_eq!(accounts[0].tokens, 0);
 | 
			
		||||
        assert_eq!(accounts[1].tokens, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_spend_wrong_source() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].tokens = 1;
 | 
			
		||||
        accounts[0].owner = from.pubkey();
 | 
			
		||||
        let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default());
 | 
			
		||||
        if let Ok(()) = process_transaction(&tx, &mut accounts) {
 | 
			
		||||
            panic!("Account not owned by SystemProgram");
 | 
			
		||||
        }
 | 
			
		||||
        assert_eq!(accounts[0].tokens, 1);
 | 
			
		||||
        assert_eq!(accounts[1].tokens, 0);
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_assign_and_allocate() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        let tx =
 | 
			
		||||
            Transaction::system_create(&from, to.pubkey(), Hash::default(), 0, 1, to.pubkey(), 0);
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert!(accounts[0].userdata.is_empty());
 | 
			
		||||
        assert_eq!(accounts[1].userdata.len(), 1);
 | 
			
		||||
        assert_eq!(accounts[1].owner, to.pubkey());
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_allocate_wrong_dest_program() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[1].owner = to.pubkey();
 | 
			
		||||
        let tx = Transaction::system_create(
 | 
			
		||||
            &from,
 | 
			
		||||
            to.pubkey(),
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            0,
 | 
			
		||||
            1,
 | 
			
		||||
            Pubkey::default(),
 | 
			
		||||
            0,
 | 
			
		||||
        );
 | 
			
		||||
        assert!(process_transaction(&tx, &mut accounts).is_err());
 | 
			
		||||
        assert!(accounts[1].userdata.is_empty());
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_allocate_wrong_source_program() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].owner = to.pubkey();
 | 
			
		||||
        let tx = Transaction::system_create(
 | 
			
		||||
            &from,
 | 
			
		||||
            to.pubkey(),
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            0,
 | 
			
		||||
            1,
 | 
			
		||||
            Pubkey::default(),
 | 
			
		||||
            0,
 | 
			
		||||
        );
 | 
			
		||||
        assert!(process_transaction(&tx, &mut accounts).is_err());
 | 
			
		||||
        assert!(accounts[1].userdata.is_empty());
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_allocate_already_allocated() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[1].userdata = vec![0, 0, 0];
 | 
			
		||||
        let tx = Transaction::system_create(
 | 
			
		||||
            &from,
 | 
			
		||||
            to.pubkey(),
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            0,
 | 
			
		||||
            2,
 | 
			
		||||
            Pubkey::default(),
 | 
			
		||||
            0,
 | 
			
		||||
        );
 | 
			
		||||
        assert!(process_transaction(&tx, &mut accounts).is_err());
 | 
			
		||||
        assert_eq!(accounts[1].userdata.len(), 3);
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_create_assign() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let program = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default()];
 | 
			
		||||
        let tx = Transaction::system_assign(&from, Hash::default(), program.pubkey(), 0);
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert_eq!(accounts[0].owner, program.pubkey());
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_move() {
 | 
			
		||||
        let from = Keypair::new();
 | 
			
		||||
        let to = Keypair::new();
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].tokens = 1;
 | 
			
		||||
        let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default());
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert_eq!(accounts[0].tokens, 0);
 | 
			
		||||
        assert_eq!(accounts[1].tokens, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_move_chain() {
 | 
			
		||||
        let froms = [&Keypair::new(), &Keypair::new()]; // also signers
 | 
			
		||||
        let tos = [froms[1].pubkey(), Keypair::new().pubkey()];
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].tokens = 4;
 | 
			
		||||
 | 
			
		||||
        let instructions = vec![
 | 
			
		||||
            Instruction::new(0, &SystemInstruction::Move { tokens: 3 }, vec![0, 1]),
 | 
			
		||||
            Instruction::new(0, &SystemInstruction::Move { tokens: 2 }, vec![1, 2]),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        let tx = Transaction::new_with_instructions(
 | 
			
		||||
            &froms,
 | 
			
		||||
            &tos,
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            0,
 | 
			
		||||
            vec![id()],
 | 
			
		||||
            instructions,
 | 
			
		||||
        );
 | 
			
		||||
        process_transaction(&tx, &mut accounts).unwrap();
 | 
			
		||||
        assert_eq!(accounts[0].tokens, 1);
 | 
			
		||||
        assert_eq!(accounts[1].tokens, 1);
 | 
			
		||||
        assert_eq!(accounts[2].tokens, 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_move_chain_no_sig() {
 | 
			
		||||
        let froms = [&Keypair::new()];
 | 
			
		||||
        let tos = [Keypair::new().pubkey(), Keypair::new().pubkey()];
 | 
			
		||||
        let mut accounts = vec![Account::default(), Account::default(), Account::default()];
 | 
			
		||||
        accounts[0].tokens = 4;
 | 
			
		||||
 | 
			
		||||
        let instructions = vec![
 | 
			
		||||
            Instruction::new(0, &SystemInstruction::Move { tokens: 3 }, vec![0, 1]),
 | 
			
		||||
            Instruction::new(0, &SystemInstruction::Move { tokens: 2 }, vec![1, 2]),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        let tx = Transaction::new_with_instructions(
 | 
			
		||||
            &froms,
 | 
			
		||||
            &tos,
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            0,
 | 
			
		||||
            vec![id()],
 | 
			
		||||
            instructions,
 | 
			
		||||
        );
 | 
			
		||||
        assert!(process_transaction(&tx, &mut accounts).is_err());
 | 
			
		||||
        // probably these are right, but nothing should be counted upon...
 | 
			
		||||
        //assert_eq!(accounts[0].tokens, 1);
 | 
			
		||||
        //assert_eq!(accounts[1].tokens, 3);
 | 
			
		||||
        //assert_eq!(accounts[2].tokens, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[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() {
 | 
			
		||||
        let keypair = Keypair::new();
 | 
			
		||||
        use budget_program;
 | 
			
		||||
 | 
			
		||||
        // CreateAccount
 | 
			
		||||
        let tx = Transaction::system_create(
 | 
			
		||||
            &keypair,
 | 
			
		||||
            keypair.pubkey(),
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            111,
 | 
			
		||||
            222,
 | 
			
		||||
            budget_program::id(),
 | 
			
		||||
            0,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            tx.userdata(0).to_vec(),
 | 
			
		||||
            vec![
 | 
			
		||||
                0, 0, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0,
 | 
			
		||||
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // CreateAccount
 | 
			
		||||
        let tx = Transaction::system_create(
 | 
			
		||||
            &keypair,
 | 
			
		||||
            keypair.pubkey(),
 | 
			
		||||
            Hash::default(),
 | 
			
		||||
            111,
 | 
			
		||||
            222,
 | 
			
		||||
            Pubkey::default(),
 | 
			
		||||
            0,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            tx.userdata(0).to_vec(),
 | 
			
		||||
            vec![
 | 
			
		||||
                0, 0, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Assign
 | 
			
		||||
        let tx = Transaction::system_assign(&keypair, Hash::default(), budget_program::id(), 0);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            tx.userdata(0).to_vec(),
 | 
			
		||||
            vec![
 | 
			
		||||
                1, 0, 0, 0, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
                0, 0, 0, 0, 0, 0, 0, 0, 0
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Move
 | 
			
		||||
        let tx = Transaction::system_move(&keypair, keypair.pubkey(), 123, Hash::default(), 0);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            tx.userdata(0).to_vec(),
 | 
			
		||||
            vec![2, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,8 +4,8 @@ use solana_sdk::hash::Hash;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::{Keypair, KeypairUtil};
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use solana_sdk::transaction::{Instruction, Transaction};
 | 
			
		||||
use system_program;
 | 
			
		||||
 | 
			
		||||
pub trait SystemTransaction {
 | 
			
		||||
    fn system_create(
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,8 @@ use solana_sdk::signature::Keypair;
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
use solana_sdk::signature::KeypairUtil;
 | 
			
		||||
use solana_sdk::system_instruction::SystemInstruction;
 | 
			
		||||
use solana_sdk::system_program;
 | 
			
		||||
use solana_sdk::transaction::{Instruction, Transaction};
 | 
			
		||||
use system_program;
 | 
			
		||||
use vote_program::{self, Vote, VoteInstruction};
 | 
			
		||||
 | 
			
		||||
pub trait VoteTransaction {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@ use ring::signature::Ed25519KeyPair;
 | 
			
		||||
use rpc::RpcSignatureStatus;
 | 
			
		||||
use rpc_request::{get_rpc_request_str, RpcClient, RpcRequest};
 | 
			
		||||
use serde_json;
 | 
			
		||||
use solana_bpf_loader;
 | 
			
		||||
use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT};
 | 
			
		||||
use solana_sdk::bpf_loader;
 | 
			
		||||
use solana_sdk::hash::Hash;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
 | 
			
		||||
@@ -431,7 +431,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
 | 
			
		||||
                last_id,
 | 
			
		||||
                1,
 | 
			
		||||
                program_userdata.len() as u64,
 | 
			
		||||
                solana_bpf_loader::id(),
 | 
			
		||||
                bpf_loader::id(),
 | 
			
		||||
                0,
 | 
			
		||||
            );
 | 
			
		||||
            send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
 | 
			
		||||
@@ -442,7 +442,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
 | 
			
		||||
            for chunk in program_userdata.chunks(USERDATA_CHUNK_SIZE) {
 | 
			
		||||
                let tx = Transaction::loader_write(
 | 
			
		||||
                    &program,
 | 
			
		||||
                    solana_bpf_loader::id(),
 | 
			
		||||
                    bpf_loader::id(),
 | 
			
		||||
                    offset,
 | 
			
		||||
                    chunk.to_vec(),
 | 
			
		||||
                    last_id,
 | 
			
		||||
@@ -457,9 +457,9 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
 | 
			
		||||
                offset += USERDATA_CHUNK_SIZE as u32;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let last_id = get_last_id(&rpc_client, &rpc_addr)?;
 | 
			
		||||
            let last_id = get_last_id(&rpc_client)?;
 | 
			
		||||
            let tx = Transaction::loader_finalize(&program, bpf_loader::id(), last_id, 0);
 | 
			
		||||
            send_and_confirm_tx(&rpc_client, &rpc_addr, &tx).map_err(|_| {
 | 
			
		||||
            send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
 | 
			
		||||
                WalletError::DynamicProgramError("Program finalize transaction failed".to_string())
 | 
			
		||||
            })?;
 | 
			
		||||
 | 
			
		||||
@@ -826,7 +826,7 @@ mod tests {
 | 
			
		||||
                            .takes_value(true)
 | 
			
		||||
                            .required(true)
 | 
			
		||||
                            .help("/path/to/program.o"),
 | 
			
		||||
                    ), // TODO: Add "loader" argument; current default is solana_bpf_loader
 | 
			
		||||
                    ), // TODO: Add "loader" argument; current default is bpf_loader
 | 
			
		||||
            ).subcommand(
 | 
			
		||||
                SubCommand::with_name("get-transaction-count")
 | 
			
		||||
                    .about("Get current transaction count"),
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ extern crate elf;
 | 
			
		||||
extern crate serde_derive;
 | 
			
		||||
extern crate solana;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
extern crate solana_bpf_loader;
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use solana::bank::Bank;
 | 
			
		||||
@@ -13,7 +12,7 @@ use solana::mint::Mint;
 | 
			
		||||
use solana::native_loader;
 | 
			
		||||
use solana::system_transaction::SystemTransaction;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use solana_bpf_loader;
 | 
			
		||||
use solana_sdk::bpf_loader;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use solana_sdk::signature::{Keypair, KeypairUtil};
 | 
			
		||||
use solana_sdk::transaction::Transaction;
 | 
			
		||||
@@ -112,7 +111,7 @@ impl Loader {
 | 
			
		||||
    pub fn new_bpf() -> Self {
 | 
			
		||||
        let mint = Mint::new(50);
 | 
			
		||||
        let bank = Bank::new(&mint);
 | 
			
		||||
        let loader = solana_bpf_loader::id();
 | 
			
		||||
        let loader = bpf_loader::id();
 | 
			
		||||
 | 
			
		||||
        Loader { mint, bank, loader }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user