diff --git a/Cargo.lock b/Cargo.lock index 4a25b3b994..fd80d50c36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 156b83c8ce..05b532fb43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/ci/publish-crate.sh b/ci/publish-crate.sh index 2f7686fd47..955875af09 100755 --- a/ci/publish-crate.sh +++ b/ci/publish-crate.sh @@ -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 diff --git a/drone/src/drone.rs b/drone/src/drone.rs index b0a5ac73a4..c104ce3645 100644 --- a/drone/src/drone.rs +++ b/drone/src/drone.rs @@ -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*/ diff --git a/programs/native/bpf_loader/src/lib.rs b/programs/native/bpf_loader/src/lib.rs index 6d6c592c69..263fbf0e7b 100644 --- a/programs/native/bpf_loader/src/lib.rs +++ b/programs/native/bpf_loader/src/lib.rs @@ -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)] diff --git a/programs/native/erc20/Cargo.toml b/programs/native/erc20/Cargo.toml index 91f63ded29..f0aabc4ce2 100644 --- a/programs/native/erc20/Cargo.toml +++ b/programs/native/erc20/Cargo.toml @@ -16,5 +16,5 @@ solana-sdk = { path = "../../../sdk", version = "0.11.0" } [lib] name = "solana_erc20" -crate-type = ["lib", "cdylib"] +crate-type = ["cdylib"] diff --git a/programs/native/erc20/src/lib.rs b/programs/native/erc20/src/lib.rs index d877d982a1..4f1380fd16 100644 --- a/programs/native/erc20/src/lib.rs +++ b/programs/native/erc20/src/lib.rs @@ -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 + }) } diff --git a/programs/native/lua_loader/src/lib.rs b/programs/native/lua_loader/src/lib.rs index bc031f6f42..78619a2c6e 100644 --- a/programs/native/lua_loader/src/lib.rs +++ b/programs/native/lua_loader/src/lib.rs @@ -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)] diff --git a/programs/native/noop/src/lib.rs b/programs/native/noop/src/lib.rs index af70664749..238ca6f013 100644 --- a/programs/native/noop/src/lib.rs +++ b/programs/native/noop/src/lib.rs @@ -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(()) } diff --git a/programs/native/system/Cargo.toml b/programs/native/system/Cargo.toml new file mode 100644 index 0000000000..6e53a3ae87 --- /dev/null +++ b/programs/native/system/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "solana-system-program" +version = "0.11.0" +description = "Solana system program" +authors = ["Solana Maintainers "] +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"] + diff --git a/programs/native/system/src/lib.rs b/programs/native/system/src/lib.rs new file mode 100644 index 0000000000..2ea0624df7 --- /dev/null +++ b/programs/native/system/src/lib.rs @@ -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) + } +} diff --git a/sdk/src/bpf_loader.rs b/sdk/src/bpf_loader.rs new file mode 100644 index 0000000000..c26157e24c --- /dev/null +++ b/sdk/src/bpf_loader.rs @@ -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) +} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 9ff8cf563f..2ca2b5582e 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -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; diff --git a/sdk/src/native_program.rs b/sdk/src/native_program.rs index 815de12cd2..f3a270850d 100644 --- a/sdk/src/native_program.rs +++ b/sdk/src/native_program.rs @@ -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, -} diff --git a/sdk/src/system_instruction.rs b/sdk/src/system_instruction.rs index 865c518bc3..9a21f04a8d 100644 --- a/sdk/src/system_instruction.rs +++ b/sdk/src/system_instruction.rs @@ -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 diff --git a/sdk/src/system_program.rs b/sdk/src/system_program.rs new file mode 100644 index 0000000000..968b2cccd5 --- /dev/null +++ b/sdk/src/system_program.rs @@ -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 +} diff --git a/src/bank.rs b/src/bank.rs index e30224c773..223ad786f1 100644 --- a/src/bank.rs +++ b/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))); diff --git a/src/budget_transaction.rs b/src/budget_transaction.rs index fa1aad100b..808a720f19 100644 --- a/src/budget_transaction.rs +++ b/src/budget_transaction.rs @@ -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]), diff --git a/src/lib.rs b/src/lib.rs index 913fa5bf7a..cf173900d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/mint.rs b/src/mint.rs index 8d3f73f9c9..fd15bb1e9d 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -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() { diff --git a/src/native_loader.rs b/src/native_loader.rs index 54f019a605..762570041f 100644 --- a/src/native_loader.rs +++ b/src/native_loader.rs @@ -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(()) } diff --git a/src/runtime.rs b/src/runtime.rs index 0eb0e33110..207e141d7f 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -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( diff --git a/src/sigverify.rs b/src/sigverify.rs index 63637b954b..d0e4c447d3 100644 --- a/src/sigverify.rs +++ b/src/sigverify.rs @@ -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] diff --git a/src/system_program.rs b/src/system_program.rs deleted file mode 100644 index 5fb547ced1..0000000000 --- a/src/system_program.rs +++ /dev/null @@ -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 = std::result::Result; - -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(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] - ); - } -} diff --git a/src/system_transaction.rs b/src/system_transaction.rs index 8237b9699d..21a617b87a 100644 --- a/src/system_transaction.rs +++ b/src/system_transaction.rs @@ -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( diff --git a/src/vote_transaction.rs b/src/vote_transaction.rs index f568f8f350..640af96243 100644 --- a/src/vote_transaction.rs +++ b/src/vote_transaction.rs @@ -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 { diff --git a/src/wallet.rs b/src/wallet.rs index 5ecc4c93d1..c1a065a6d7 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -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 Result Result 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 } }