From 08ba27627d1d8eaede0691e3885135896a09865c Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 10 Jan 2020 13:20:15 -0800 Subject: [PATCH] Direct entrypoint for execution (#7746) --- programs/bpf_loader/src/lib.rs | 129 ++++----- programs/librapay/src/lib.rs | 4 +- programs/librapay/src/librapay_instruction.rs | 28 +- programs/librapay/src/librapay_transaction.rs | 3 +- programs/move_loader/src/lib.rs | 4 +- programs/move_loader/src/processor.rs | 252 ++++++++++-------- runtime/src/message_processor.rs | 72 +---- sdk/src/instruction_processor_utils.rs | 6 + sdk/src/loader_instruction.rs | 8 - 9 files changed, 230 insertions(+), 276 deletions(-) diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 2eb897f26..6d8bf9efa 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -9,7 +9,7 @@ use solana_rbpf::{memory_region::MemoryRegion, EbpfVm}; use solana_sdk::{ account::KeyedAccount, instruction::InstructionError, - instruction_processor_utils::{limited_deserialize, next_keyed_account}, + instruction_processor_utils::{is_executable, limited_deserialize, next_keyed_account}, loader_instruction::LoaderInstruction, pubkey::Pubkey, sysvar::rent, @@ -92,12 +92,57 @@ pub fn deserialize_parameters(keyed_accounts: &mut [KeyedAccount], buffer: &[u8] pub fn process_instruction( program_id: &Pubkey, keyed_accounts: &mut [KeyedAccount], - ix_data: &[u8], + instruction_data: &[u8], ) -> Result<(), InstructionError> { solana_logger::setup_with_default("solana=info"); - if let Ok(instruction) = limited_deserialize(ix_data) { - match instruction { + if keyed_accounts.is_empty() { + warn!("No account keys"); + return Err(InstructionError::NotEnoughAccountKeys); + } + + if is_executable(keyed_accounts) { + let mut keyed_accounts_iter = keyed_accounts.iter_mut(); + let program = next_keyed_account(&mut keyed_accounts_iter)?; + + if !program.account.executable { + warn!("BPF program account not executable"); + return Err(InstructionError::AccountNotExecutable); + } + let (mut vm, heap_region) = match create_vm(&program.account.data) { + Ok(info) => info, + Err(e) => { + warn!("Failed to create BPF VM: {}", e); + return Err(InstructionError::GenericError); + } + }; + let parameter_accounts = keyed_accounts_iter.into_slice(); + let mut parameter_bytes = + serialize_parameters(program_id, parameter_accounts, &instruction_data); + + info!("Call BPF program"); + match vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) { + Ok(status) => match u32::try_from(status) { + Ok(status) => { + if status > 0 { + warn!("BPF program failed: {}", status); + return Err(InstructionError::CustomError(status)); + } + } + Err(e) => { + warn!("BPF VM encountered invalid status: {}", e); + return Err(InstructionError::GenericError); + } + }, + Err(e) => { + warn!("BPF VM failed to run program: {}", e); + return Err(InstructionError::GenericError); + } + } + deserialize_parameters(parameter_accounts, ¶meter_bytes); + info!("BPF program success"); + } else if !keyed_accounts.is_empty() { + match limited_deserialize(instruction_data)? { LoaderInstruction::Write { offset, bytes } => { let mut keyed_accounts_iter = keyed_accounts.iter_mut(); let program = next_keyed_account(&mut keyed_accounts_iter)?; @@ -138,51 +183,7 @@ pub fn process_instruction( program.account.executable = true; info!("Finalize: account {:?}", program.signer_key().unwrap()); } - LoaderInstruction::InvokeMain { data } => { - let mut keyed_accounts_iter = keyed_accounts.iter_mut(); - let program = next_keyed_account(&mut keyed_accounts_iter)?; - - if !program.account.executable { - warn!("BPF program account not executable"); - return Err(InstructionError::AccountNotExecutable); - } - let (mut vm, heap_region) = match create_vm(&program.account.data) { - Ok(info) => info, - Err(e) => { - warn!("Failed to create BPF VM: {}", e); - return Err(InstructionError::GenericError); - } - }; - let parameter_accounts = keyed_accounts_iter.into_slice(); - let mut parameter_bytes = - serialize_parameters(program_id, parameter_accounts, &data); - - info!("Call BPF program"); - match vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) { - Ok(status) => match u32::try_from(status) { - Ok(status) => { - if status > 0 { - warn!("BPF program failed: {}", status); - return Err(InstructionError::CustomError(status)); - } - } - Err(e) => { - warn!("BPF VM encountered invalid status: {}", e); - return Err(InstructionError::GenericError); - } - }, - Err(e) => { - warn!("BPF VM failed to run program: {}", e); - return Err(InstructionError::GenericError); - } - } - deserialize_parameters(parameter_accounts, ¶meter_bytes); - info!("BPF program success"); - } } - } else { - warn!("Invalid instruction data: {:?}", ix_data); - return Err(InstructionError::InvalidInstructionData); } Ok(()) } @@ -218,7 +219,7 @@ mod tests { let program_key = Pubkey::new_rand(); let mut program_account = Account::new(1, 0, &program_id); let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)]; - let ix_data = bincode::serialize(&LoaderInstruction::Write { + let instruction_data = bincode::serialize(&LoaderInstruction::Write { offset: 3, bytes: vec![1, 2, 3], }) @@ -227,13 +228,13 @@ mod tests { // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &mut vec![], &ix_data) + process_instruction(&program_id, &mut vec![], &instruction_data) ); // Case: Not signed assert_eq!( Err(InstructionError::MissingRequiredSignature), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); // Case: Write bytes to an offset @@ -241,7 +242,7 @@ mod tests { keyed_accounts[0].account.data = vec![0; 6]; assert_eq!( Ok(()), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); assert_eq!(vec![0, 0, 0, 1, 2, 3], keyed_accounts[0].account.data); @@ -250,7 +251,7 @@ mod tests { keyed_accounts[0].account.data = vec![0; 5]; assert_eq!( Err(InstructionError::AccountDataTooSmall), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); } @@ -266,12 +267,12 @@ mod tests { let mut program_account = Account::new(rent.minimum_balance(elf.len()), 0, &program_id); program_account.data = elf; let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)]; - let ix_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap(); + let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap(); // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &mut vec![], &ix_data) + process_instruction(&program_id, &mut vec![], &instruction_data) ); let mut rent_account = rent::create_account(1, &rent); @@ -280,7 +281,7 @@ mod tests { // Case: Not signed assert_eq!( Err(InstructionError::MissingRequiredSignature), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); // Case: Finalize @@ -290,9 +291,10 @@ mod tests { ]; assert_eq!( Ok(()), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); assert!(keyed_accounts[0].account.executable); + program_account.executable = false; // Un-finalize the account // Case: Finalize program_account.data[0] = 0; // bad elf @@ -302,7 +304,7 @@ mod tests { ]; assert_eq!( Err(InstructionError::InvalidAccountData), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &instruction_data) ); } @@ -320,25 +322,24 @@ mod tests { program_account.executable = true; let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &mut program_account)]; - let ix_data = bincode::serialize(&LoaderInstruction::InvokeMain { data: vec![] }).unwrap(); // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &mut vec![], &ix_data) + process_instruction(&program_id, &mut vec![], &vec![]) ); // Case: Only a program account assert_eq!( Ok(()), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &vec![]) ); // Case: Account not executable keyed_accounts[0].account.executable = false; assert_eq!( - Err(InstructionError::AccountNotExecutable), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + Err(InstructionError::InvalidInstructionData), + process_instruction(&program_id, &mut keyed_accounts, &vec![]) ); keyed_accounts[0].account.executable = true; @@ -351,7 +352,7 @@ mod tests { )); assert_eq!( Ok(()), - process_instruction(&program_id, &mut keyed_accounts, &ix_data) + process_instruction(&program_id, &mut keyed_accounts, &vec![]) ); } } diff --git a/programs/librapay/src/lib.rs b/programs/librapay/src/lib.rs index a2a2edf9f..2ba12a014 100644 --- a/programs/librapay/src/lib.rs +++ b/programs/librapay/src/lib.rs @@ -5,7 +5,7 @@ pub mod librapay_transaction; extern crate solana_move_loader_program; -use solana_move_loader_program::account_state::LibraAccountState; +use solana_move_loader_program::{account_state::LibraAccountState, processor::MoveProcessor}; use solana_runtime::loader_utils::load_program; use solana_sdk::{ account::KeyedAccount, @@ -86,5 +86,5 @@ pub fn process_instruction( keyed_accounts: &mut [KeyedAccount], data: &[u8], ) -> Result<(), InstructionError> { - solana_move_loader_program::processor::process_instruction(program_id, keyed_accounts, data) + MoveProcessor::process_instruction(program_id, keyed_accounts, data) } diff --git a/programs/librapay/src/librapay_instruction.rs b/programs/librapay/src/librapay_instruction.rs index 52b2d3745..6664287f0 100644 --- a/programs/librapay/src/librapay_instruction.rs +++ b/programs/librapay/src/librapay_instruction.rs @@ -1,17 +1,17 @@ -use bincode; -use solana_move_loader_program::{account_state::pubkey_to_address, processor::InvokeCommand}; +use solana_move_loader_program::{ + account_state::pubkey_to_address, + processor::{Executable, MoveLoaderInstruction}, +}; use solana_sdk::{ instruction::{AccountMeta, Instruction}, - loader_instruction::LoaderInstruction, pubkey::Pubkey, }; use types::{account_config, transaction::TransactionArgument}; pub fn genesis(genesis_pubkey: &Pubkey, microlibras: u64) -> Instruction { - let data = bincode::serialize(&InvokeCommand::CreateGenesis(microlibras)).unwrap(); - let ix_data = LoaderInstruction::InvokeMain { data }; + let instruction_data = MoveLoaderInstruction::CreateGenesis(microlibras); let accounts = vec![AccountMeta::new(*genesis_pubkey, true)]; - Instruction::new(solana_sdk::move_loader::id(), &ix_data, accounts) + Instruction::new(solana_sdk::move_loader::id(), &instruction_data, accounts) } pub fn mint( @@ -25,13 +25,11 @@ pub fn mint( TransactionArgument::U64(microlibras), ]; - let data = bincode::serialize(&InvokeCommand::RunScript { + let instruction_data = Executable::RunScript { sender_address: account_config::association_address(), function_name: "main".to_string(), args, - }) - .unwrap(); - let ix_data = LoaderInstruction::InvokeMain { data }; + }; let accounts = vec![ AccountMeta::new_readonly(*script_pubkey, false), @@ -39,7 +37,7 @@ pub fn mint( AccountMeta::new(*to_pubkey, false), ]; - Instruction::new(solana_sdk::move_loader::id(), &ix_data, accounts) + Instruction::new(solana_sdk::move_loader::id(), &instruction_data, accounts) } pub fn transfer( @@ -54,13 +52,11 @@ pub fn transfer( TransactionArgument::U64(microlibras), ]; - let data = bincode::serialize(&InvokeCommand::RunScript { + let instruction_data = Executable::RunScript { sender_address: pubkey_to_address(from_pubkey), function_name: "main".to_string(), args, - }) - .unwrap(); - let ix_data = LoaderInstruction::InvokeMain { data }; + }; let accounts = vec![ AccountMeta::new_readonly(*script_pubkey, false), @@ -69,7 +65,7 @@ pub fn transfer( AccountMeta::new(*to_pubkey, false), ]; - Instruction::new(solana_sdk::move_loader::id(), &ix_data, accounts) + Instruction::new(solana_sdk::move_loader::id(), &instruction_data, accounts) } #[cfg(test)] diff --git a/programs/librapay/src/librapay_transaction.rs b/programs/librapay/src/librapay_transaction.rs index ed741dfbc..9c8d6a5a6 100644 --- a/programs/librapay/src/librapay_transaction.rs +++ b/programs/librapay/src/librapay_transaction.rs @@ -151,6 +151,7 @@ pub fn get_libra_balance( mod tests { use super::*; use crate::{create_genesis, upload_mint_script, upload_payment_script}; + use solana_move_loader_program::processor::MoveProcessor; use solana_runtime::bank::Bank; use solana_runtime::bank_client::BankClient; use solana_sdk::genesis_config::create_genesis_config; @@ -163,7 +164,7 @@ mod tests { let mut bank = Bank::new(&genesis_config); bank.add_instruction_processor( solana_sdk::move_loader::id(), - solana_move_loader_program::processor::process_instruction, + MoveProcessor::process_instruction, ); let shared_bank = Arc::new(bank); let bank_client = BankClient::new_shared(&shared_bank); diff --git a/programs/move_loader/src/lib.rs b/programs/move_loader/src/lib.rs index e2aac1db1..ef7cc84f6 100644 --- a/programs/move_loader/src/lib.rs +++ b/programs/move_loader/src/lib.rs @@ -3,10 +3,10 @@ pub mod data_store; pub mod error_mappers; pub mod processor; -use crate::processor::process_instruction; +use crate::processor::MoveProcessor; solana_sdk::declare_program!( solana_sdk::move_loader::ID, solana_move_loader_program, - process_instruction + MoveProcessor::process_instruction ); diff --git a/programs/move_loader/src/processor.rs b/programs/move_loader/src/processor.rs index c652625c3..cf694d9ec 100644 --- a/programs/move_loader/src/processor.rs +++ b/programs/move_loader/src/processor.rs @@ -7,8 +7,7 @@ use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ account::KeyedAccount, instruction::InstructionError, - instruction_processor_utils::{limited_deserialize, next_keyed_account}, - loader_instruction::LoaderInstruction, + instruction_processor_utils::{is_executable, limited_deserialize, next_keyed_account}, move_loader::id, pubkey::Pubkey, sysvar::rent, @@ -36,30 +35,42 @@ use vm_runtime::{ }; use vm_runtime_types::value::Value; -pub fn process_instruction( - _program_id: &Pubkey, - keyed_accounts: &mut [KeyedAccount], - data: &[u8], -) -> Result<(), InstructionError> { - solana_logger::setup(); +/// Instruction data passed to perform a loader operation, must be based +/// on solana_sdk::loader_instruction::LoaderInstruction +#[derive(Serialize, Deserialize, Debug)] +pub enum MoveLoaderInstruction { + /// Write program data into an account + /// + /// * key[0] - the account to write into. + /// + /// The transaction must be signed by key[0] + Write { + offset: u32, + #[serde(with = "serde_bytes")] + bytes: Vec, + }, - match limited_deserialize(data)? { - LoaderInstruction::Write { offset, bytes } => { - MoveProcessor::do_write(keyed_accounts, offset, &bytes) - } - LoaderInstruction::Finalize => MoveProcessor::do_finalize(keyed_accounts), - LoaderInstruction::InvokeMain { data } => { - MoveProcessor::do_invoke_main(keyed_accounts, &data) - } - } + /// Finalize an account loaded with program data for execution. + /// The exact preparation steps is loader specific but on success the loader must set the executable + /// bit of the Account + /// + /// * key[0] - the account to prepare for execution + /// * key[1] - rent sysvar account + /// + /// The transaction must be signed by key[0] + Finalize, + + /// Create a new genesis account + /// + /// * key[0] - the account to write the genesis into + /// + /// The transaction must be signed by key[0] + CreateGenesis(u64), } -/// Command to invoke -#[derive(Debug, Serialize, Deserialize)] -pub enum InvokeCommand { - /// Create a new genesis account - CreateGenesis(u64), - /// run a Move script +/// Instruction data passed when executing a Move script +#[derive(Serialize, Deserialize, Debug)] +pub enum Executable { RunScript { /// Sender of the "transaction", the "sender" who is running this script sender_address: AccountAddress, @@ -349,72 +360,98 @@ impl MoveProcessor { Ok(()) } + pub fn do_create_genesis( + keyed_accounts: &mut [KeyedAccount], + amount: u64, + ) -> Result<(), InstructionError> { + let mut keyed_accounts_iter = keyed_accounts.iter_mut(); + let script = next_keyed_account(&mut keyed_accounts_iter)?; + + if script.account.owner != id() { + debug!("Error: Move script account not owned by Move loader"); + return Err(InstructionError::InvalidArgument); + } + + match limited_deserialize(&script.account.data)? { + LibraAccountState::Unallocated => Self::serialize_and_enforce_length( + &LibraAccountState::create_genesis(amount)?, + &mut script.account.data, + ), + _ => { + debug!("Error: Must provide an unallocated account"); + Err(InstructionError::InvalidArgument) + } + } + } + pub fn do_invoke_main( keyed_accounts: &mut [KeyedAccount], - data: &[u8], + sender_address: AccountAddress, + function_name: String, + args: Vec, ) -> Result<(), InstructionError> { - match limited_deserialize(&data)? { - InvokeCommand::CreateGenesis(amount) => { - let mut keyed_accounts_iter = keyed_accounts.iter_mut(); - let script = next_keyed_account(&mut keyed_accounts_iter)?; + let mut keyed_accounts_iter = keyed_accounts.iter_mut(); + let script = next_keyed_account(&mut keyed_accounts_iter)?; - if script.account.owner != id() { - debug!("Error: Move script account not owned by Move loader"); - return Err(InstructionError::InvalidArgument); - } + trace!( + "Run script {:?} with entrypoint {:?}", + script.unsigned_key(), + function_name + ); - match limited_deserialize(&script.account.data)? { - LibraAccountState::Unallocated => Self::serialize_and_enforce_length( - &LibraAccountState::create_genesis(amount)?, - &mut script.account.data, - ), - _ => { - debug!("Error: Must provide an unallocated account"); - Err(InstructionError::InvalidArgument) - } - } - } - InvokeCommand::RunScript { - sender_address, - function_name, - args, - } => { - let mut keyed_accounts_iter = keyed_accounts.iter_mut(); - let script = next_keyed_account(&mut keyed_accounts_iter)?; + if script.account.owner != id() { + debug!("Error: Move script account not owned by Move loader"); + return Err(InstructionError::InvalidArgument); + } + if !script.account.executable { + debug!("Error: Move script account not executable"); + return Err(InstructionError::AccountNotExecutable); + } - trace!( - "Run script {:?} with entrypoint {:?}", - script.unsigned_key(), - function_name - ); + let data_accounts = keyed_accounts_iter.into_slice(); - if script.account.owner != id() { - debug!("Error: Move script account not owned by Move loader"); - return Err(InstructionError::InvalidArgument); - } - if !script.account.executable { - debug!("Error: Move script account not executable"); - return Err(InstructionError::AccountNotExecutable); - } + let mut data_store = Self::keyed_accounts_to_data_store(&data_accounts)?; + let verified_script = Self::deserialize_verified_script(&script.account.data)?; - let data_accounts = keyed_accounts_iter.into_slice(); + let output = Self::execute( + sender_address, + &function_name, + args, + verified_script, + &data_store, + )?; + for event in output.events() { + trace!("Event: {:?}", event); + } - let mut data_store = Self::keyed_accounts_to_data_store(&data_accounts)?; - let verified_script = Self::deserialize_verified_script(&script.account.data)?; + data_store.apply_write_set(&output.write_set()); + Self::data_store_to_keyed_accounts(data_store, data_accounts) + } - let output = Self::execute( + pub fn process_instruction( + _program_id: &Pubkey, + keyed_accounts: &mut [KeyedAccount], + instruction_data: &[u8], + ) -> Result<(), InstructionError> { + solana_logger::setup(); + + if is_executable(keyed_accounts) { + match limited_deserialize(&instruction_data)? { + Executable::RunScript { sender_address, - &function_name, + function_name, args, - verified_script, - &data_store, - )?; - for event in output.events() { - trace!("Event: {:?}", event); + } => Self::do_invoke_main(keyed_accounts, sender_address, function_name, args), + } + } else { + match limited_deserialize(instruction_data)? { + MoveLoaderInstruction::Write { offset, bytes } => { + Self::do_write(keyed_accounts, offset, &bytes) + } + MoveLoaderInstruction::Finalize => Self::do_finalize(keyed_accounts), + MoveLoaderInstruction::CreateGenesis(amount) => { + Self::do_create_genesis(keyed_accounts, amount) } - - data_store.apply_write_set(&output.write_set()); - Self::data_store_to_keyed_accounts(data_store, data_accounts) } } } @@ -484,11 +521,7 @@ mod tests { false, &mut unallocated.account, )]; - MoveProcessor::do_invoke_main( - &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::CreateGenesis(amount)).unwrap(), - ) - .unwrap(); + MoveProcessor::do_create_genesis(&mut keyed_accounts, amount).unwrap(); assert_eq!( bincode::deserialize::( @@ -524,12 +557,9 @@ mod tests { MoveProcessor::do_invoke_main( &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::RunScript { - sender_address, - function_name: "main".to_string(), - args: vec![], - }) - .unwrap(), + sender_address, + "main".to_string(), + vec![], ) .unwrap(); } @@ -588,12 +618,9 @@ mod tests { assert_eq!( MoveProcessor::do_invoke_main( &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::RunScript { - sender_address, - function_name: "main".to_string(), - args: vec![], - }) - .unwrap(), + sender_address, + "main".to_string(), + vec![], ), Err(InstructionError::CustomError(4002)) ); @@ -668,15 +695,12 @@ mod tests { let amount = 2; MoveProcessor::do_invoke_main( &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::RunScript { - sender_address: sender.address.clone(), - function_name: "main".to_string(), - args: vec![ - TransactionArgument::Address(payee.address.clone()), - TransactionArgument::U64(amount), - ], - }) - .unwrap(), + sender.address.clone(), + "main".to_string(), + vec![ + TransactionArgument::Address(payee.address.clone()), + TransactionArgument::U64(amount), + ], ) .unwrap(); @@ -768,12 +792,9 @@ mod tests { MoveProcessor::do_invoke_main( &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::RunScript { - sender_address: sender.address.clone(), - function_name: "main".to_string(), - args: vec![TransactionArgument::Address(payee.address.clone())], - }) - .unwrap(), + sender.address.clone(), + "main".to_string(), + vec![TransactionArgument::Address(payee.address.clone())], ) .unwrap(); @@ -819,15 +840,12 @@ mod tests { MoveProcessor::do_invoke_main( &mut keyed_accounts, - &bincode::serialize(&InvokeCommand::RunScript { - sender_address: account_config::association_address(), - function_name: "main".to_string(), - args: vec![ - TransactionArgument::Address(pubkey_to_address(&payee.key)), - TransactionArgument::U64(amount), - ], - }) - .unwrap(), + account_config::association_address(), + "main".to_string(), + vec![ + TransactionArgument::Address(pubkey_to_address(&payee.key)), + TransactionArgument::U64(amount), + ], ) .unwrap(); diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 580d4afc6..4ced6abfd 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -5,13 +5,11 @@ use solana_sdk::account::{create_keyed_readonly_accounts, Account, KeyedAccount} use solana_sdk::clock::Epoch; use solana_sdk::instruction::{CompiledInstruction, InstructionError}; use solana_sdk::instruction_processor_utils; -use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::message::Message; use solana_sdk::pubkey::Pubkey; use solana_sdk::system_program; use solana_sdk::transaction::TransactionError; use std::collections::HashMap; -use std::io::Write; use std::sync::RwLock; #[cfg(unix)] @@ -162,27 +160,6 @@ pub fn verify_account_changes( Ok(()) } -/// Return instruction data to pass to process_instruction(). -/// When a loader is detected, the instruction data is wrapped with a LoaderInstruction -/// to signal to the loader that the instruction data should be used as arguments when -/// invoking a "main()" function. -fn get_loader_instruction_data<'a>( - loaders: &[(Pubkey, Account)], - ix_data: &'a [u8], - loader_ix_data: &'a mut Vec, -) -> &'a [u8] { - if loaders.len() > 1 { - let ix = LoaderInstruction::InvokeMain { - data: ix_data.to_vec(), - }; - let ix_data = bincode::serialize(&ix).unwrap(); - loader_ix_data.write_all(&ix_data).unwrap(); - loader_ix_data - } else { - ix_data - } -} - pub type ProcessInstruction = fn(&Pubkey, &mut [KeyedAccount], &[u8]) -> Result<(), InstructionError>; @@ -231,14 +208,6 @@ impl MessageProcessor { program_accounts: &mut [&mut Account], ) -> Result<(), InstructionError> { let program_id = instruction.program_id(&message.account_keys); - - let mut loader_ix_data = vec![]; - let ix_data = get_loader_instruction_data( - executable_accounts, - &instruction.data, - &mut loader_ix_data, - ); - let mut keyed_accounts = create_keyed_readonly_accounts(executable_accounts); let mut keyed_accounts2: Vec<_> = instruction .accounts @@ -272,14 +241,18 @@ impl MessageProcessor { let loader_id = keyed_accounts[0].unsigned_key(); for (id, process_instruction) in &self.instruction_processors { if id == loader_id { - return process_instruction(&program_id, &mut keyed_accounts[1..], &ix_data); + return process_instruction( + &program_id, + &mut keyed_accounts[1..], + &instruction.data, + ); } } native_loader::invoke_entrypoint( &program_id, &mut keyed_accounts, - ix_data, + &instruction.data, &self.symbol_cache, ) } @@ -876,37 +849,4 @@ mod tests { )) ); } - - #[test] - fn test_get_loader_instruction_data() { - // First ensure the ix_data is unaffected if not invoking via a loader. - let ix_data = [1]; - let mut loader_ix_data = vec![]; - - let native_pubkey = Pubkey::new_rand(); - let native_loader = (native_pubkey, Account::new(0, 0, &native_pubkey)); - assert_eq!( - get_loader_instruction_data(&[native_loader.clone()], &ix_data, &mut loader_ix_data), - &ix_data - ); - - // Now ensure the ix_data is wrapped when there's a loader present. - let acme_pubkey = Pubkey::new_rand(); - let acme_loader = (acme_pubkey, Account::new(0, 0, &native_pubkey)); - let expected_ix = LoaderInstruction::InvokeMain { - data: ix_data.to_vec(), - }; - let expected_ix_data = bincode::serialize(&expected_ix).unwrap(); - assert_eq!( - get_loader_instruction_data( - &[native_loader.clone(), acme_loader.clone()], - &ix_data, - &mut loader_ix_data - ), - &expected_ix_data[..] - ); - - // Note there was an allocation in the input vector. - assert_eq!(loader_ix_data, expected_ix_data); - } } diff --git a/sdk/src/instruction_processor_utils.rs b/sdk/src/instruction_processor_utils.rs index 67515f8df..476bac6c9 100644 --- a/sdk/src/instruction_processor_utils.rs +++ b/sdk/src/instruction_processor_utils.rs @@ -113,6 +113,12 @@ pub fn next_keyed_account(iter: &mut I) -> Result bool { + !keyed_accounts.is_empty() && keyed_accounts[0].account.executable +} + pub fn limited_deserialize(data: &[u8]) -> Result where T: serde::de::DeserializeOwned, diff --git a/sdk/src/loader_instruction.rs b/sdk/src/loader_instruction.rs index ecbe0d669..556ae3c4b 100644 --- a/sdk/src/loader_instruction.rs +++ b/sdk/src/loader_instruction.rs @@ -24,14 +24,6 @@ pub enum LoaderInstruction { /// /// The transaction must be signed by key[0] Finalize, - - /// Invoke the "main" entrypoint with the given data. - /// - /// * key[0] - an executable account - InvokeMain { - #[serde(with = "serde_bytes")] - data: Vec, - }, } pub fn write(