Move system_program out of src/
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user