Direct entrypoint for execution (#7746)
This commit is contained in:
@ -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
|
||||
);
|
||||
|
@ -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<u8>,
|
||||
},
|
||||
|
||||
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<TransactionArgument>,
|
||||
) -> 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::<LibraAccountState>(
|
||||
@ -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();
|
||||
|
||||
|
Reference in New Issue
Block a user