@@ -10,7 +10,7 @@ use solana_sdk::{
|
||||
};
|
||||
use types::{
|
||||
account_address::AccountAddress,
|
||||
transaction::{Program, TransactionArgument, TransactionOutput},
|
||||
transaction::{TransactionArgument, TransactionOutput},
|
||||
};
|
||||
use vm::{
|
||||
access::ModuleAccess,
|
||||
@@ -24,7 +24,6 @@ use vm_runtime::{
|
||||
module_adapter::ModuleFetcherImpl,
|
||||
module_cache::{BlockModuleCache, ModuleCache, VMModuleCache},
|
||||
},
|
||||
static_verify_program,
|
||||
txn_executor::TransactionExecutor,
|
||||
value::Local,
|
||||
};
|
||||
@@ -88,17 +87,21 @@ impl MoveProcessor {
|
||||
debug!("Error: Script deserialize failed: {:?}", err);
|
||||
InstructionError::InvalidInstructionData
|
||||
}
|
||||
fn map_vm_verification_error(
|
||||
err: std::vec::Vec<vm::errors::VerificationStatus>,
|
||||
) -> InstructionError {
|
||||
debug!("Error: Script verification failed: {:?}", err);
|
||||
InstructionError::InvalidInstructionData
|
||||
}
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionError {
|
||||
debug!("Error: Account data: {:?}", err);
|
||||
InstructionError::InvalidAccountData
|
||||
}
|
||||
fn map_vm_verification_error(
|
||||
err: (CompiledModule, Vec<vm::errors::VerificationError>),
|
||||
) -> InstructionError {
|
||||
debug!("Error: Script verification failed: {:?}", err.1);
|
||||
InstructionError::InvalidInstructionData
|
||||
}
|
||||
fn map_failure_error(err: failure::Error) -> InstructionError {
|
||||
debug!("Error: Script verification failed: {:?}", err);
|
||||
InstructionError::InvalidInstructionData
|
||||
}
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn missing_account() -> InstructionError {
|
||||
debug!("Error: Missing account");
|
||||
@@ -118,19 +121,81 @@ impl MoveProcessor {
|
||||
locals
|
||||
}
|
||||
|
||||
fn deserialize_program(
|
||||
program: &Program,
|
||||
) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> {
|
||||
let compiled_script =
|
||||
CompiledScript::deserialize(program.code()).map_err(Self::map_vm_binary_error)?;
|
||||
let mut compiled_modules = vec![];
|
||||
for module_bytes in program.modules().iter() {
|
||||
let compiled_module =
|
||||
CompiledModule::deserialize(module_bytes).map_err(Self::map_vm_binary_error)?;
|
||||
compiled_modules.push(compiled_module);
|
||||
fn serialize_verified_program(
|
||||
script: &VerifiedScript,
|
||||
modules: &[VerifiedModule],
|
||||
) -> Result<(Vec<u8>), InstructionError> {
|
||||
let mut script_bytes = vec![];
|
||||
script
|
||||
.as_inner()
|
||||
.serialize(&mut script_bytes)
|
||||
.map_err(Self::map_failure_error)?;
|
||||
let mut modules_bytes = vec![];
|
||||
for module in modules.iter() {
|
||||
let mut buf = vec![];
|
||||
module
|
||||
.as_inner()
|
||||
.serialize(&mut buf)
|
||||
.map_err(Self::map_failure_error)?;
|
||||
modules_bytes.push(buf);
|
||||
}
|
||||
bincode::serialize(&LibraAccountState::VerifiedProgram {
|
||||
script_bytes,
|
||||
modules_bytes,
|
||||
})
|
||||
.map_err(Self::map_data_error)
|
||||
}
|
||||
|
||||
Ok((compiled_script, compiled_modules))
|
||||
fn deserialize_compiled_program(
|
||||
data: &[u8],
|
||||
) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> {
|
||||
let (script_bytes, modules_bytes) =
|
||||
match bincode::deserialize(data).map_err(Self::map_data_error)? {
|
||||
LibraAccountState::CompiledProgram {
|
||||
script_bytes,
|
||||
modules_bytes,
|
||||
} => (script_bytes, modules_bytes),
|
||||
_ => {
|
||||
debug!("Error: Program account does not contain a program");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
};
|
||||
|
||||
let script =
|
||||
CompiledScript::deserialize(&script_bytes).map_err(Self::map_vm_binary_error)?;
|
||||
let modules = modules_bytes
|
||||
.iter()
|
||||
.map(|bytes| CompiledModule::deserialize(&bytes))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(Self::map_vm_binary_error)?;
|
||||
|
||||
Ok((script, modules))
|
||||
}
|
||||
|
||||
fn deserialize_verified_program(
|
||||
data: &[u8],
|
||||
) -> Result<(VerifiedScript, Vec<VerifiedModule>), InstructionError> {
|
||||
let (script_bytes, modules_bytes) =
|
||||
match bincode::deserialize(data).map_err(Self::map_data_error)? {
|
||||
LibraAccountState::VerifiedProgram {
|
||||
script_bytes,
|
||||
modules_bytes,
|
||||
} => (script_bytes, modules_bytes),
|
||||
_ => {
|
||||
debug!("Error: Program account does not contain a program");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
};
|
||||
|
||||
let script =
|
||||
VerifiedScript::deserialize(&script_bytes).map_err(Self::map_vm_binary_error)?;
|
||||
let modules = modules_bytes
|
||||
.iter()
|
||||
.map(|bytes| VerifiedModule::deserialize(&bytes))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(Self::map_vm_binary_error)?;
|
||||
|
||||
Ok((script, modules))
|
||||
}
|
||||
|
||||
fn execute(
|
||||
@@ -221,7 +286,21 @@ impl MoveProcessor {
|
||||
debug!("Error: key[0] did not sign the transaction");
|
||||
return Err(InstructionError::GenericError);
|
||||
}
|
||||
|
||||
let (compiled_script, compiled_modules) =
|
||||
Self::deserialize_compiled_program(&keyed_accounts[PROGRAM_INDEX].account.data)?;
|
||||
|
||||
let verified_script = VerifiedScript::new(compiled_script).unwrap();
|
||||
let verified_modules = compiled_modules
|
||||
.into_iter()
|
||||
.map(VerifiedModule::new)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(Self::map_vm_verification_error)?;
|
||||
|
||||
keyed_accounts[PROGRAM_INDEX].account.data =
|
||||
Self::serialize_verified_program(&verified_script, &verified_modules)?;
|
||||
keyed_accounts[PROGRAM_INDEX].account.executable = true;
|
||||
|
||||
info!(
|
||||
"Finalize: {:?}",
|
||||
keyed_accounts[PROGRAM_INDEX]
|
||||
@@ -249,27 +328,11 @@ impl MoveProcessor {
|
||||
}
|
||||
|
||||
let invoke_info: InvokeInfo = bincode::deserialize(&data).map_err(Self::map_data_error)?;
|
||||
|
||||
let program = match bincode::deserialize(&keyed_accounts[0].account.data)
|
||||
.map_err(Self::map_data_error)?
|
||||
{
|
||||
LibraAccountState::Program(program) => program,
|
||||
_ => {
|
||||
debug!("Error: First account must contain the program bits");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
};
|
||||
|
||||
let mut data_store = Self::keyed_accounts_to_data_store(&keyed_accounts[GENESIS_INDEX..])?;
|
||||
let (verified_script, verified_modules) =
|
||||
Self::deserialize_verified_program(&keyed_accounts[PROGRAM_INDEX].account.data)?;
|
||||
|
||||
let (compiled_script, compiled_modules) = Self::deserialize_program(&program)?;
|
||||
let (script, modules) = static_verify_program(
|
||||
&invoke_info.sender_address,
|
||||
compiled_script,
|
||||
compiled_modules,
|
||||
)
|
||||
.map_err(Self::map_vm_verification_error)?;
|
||||
let output = Self::execute(invoke_info, script, modules, &data_store)?;
|
||||
let output = Self::execute(invoke_info, verified_script, verified_modules, &data_store)?;
|
||||
for event in output.events() {
|
||||
trace!("Event: {:?}", event);
|
||||
}
|
||||
@@ -314,6 +377,18 @@ mod tests {
|
||||
use language_e2e_tests::account::AccountResource;
|
||||
use solana_sdk::account::Account;
|
||||
|
||||
#[test]
|
||||
fn test_finalize() {
|
||||
solana_logger::setup();
|
||||
|
||||
let code = "main() { return; }";
|
||||
let sender_address = AccountAddress::default();
|
||||
let mut program = LibraAccount::create_program(&sender_address, code, vec![]);
|
||||
let mut keyed_accounts = vec![KeyedAccount::new(&program.key, true, &mut program.account)];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let (_, _) = MoveProcessor::deserialize_verified_program(&program.account.data).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invoke_main() {
|
||||
solana_logger::setup();
|
||||
@@ -324,9 +399,10 @@ mod tests {
|
||||
let mut genesis = LibraAccount::create_genesis();
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address,
|
||||
function_name: "main".to_string(),
|
||||
@@ -354,9 +430,11 @@ mod tests {
|
||||
let mut genesis = LibraAccount::create_genesis();
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address,
|
||||
function_name: "main".to_string(),
|
||||
@@ -413,11 +491,12 @@ mod tests {
|
||||
let genesis = &mut genesis[1];
|
||||
let sender = &mut sender[0];
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
KeyedAccount::new(&sender.key, false, &mut sender.account),
|
||||
KeyedAccount::new(&payee.key, false, &mut payee.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
|
||||
let amount = 2;
|
||||
let invoke_info = InvokeInfo {
|
||||
@@ -475,10 +554,11 @@ mod tests {
|
||||
let mut program = LibraAccount::create_program(&payee.address, code, vec![]);
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
KeyedAccount::new(&payee.key, false, &mut payee.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address: payee.address,
|
||||
function_name: "main".to_string(),
|
||||
@@ -509,10 +589,11 @@ mod tests {
|
||||
let mut genesis = LibraAccount::create_genesis();
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
KeyedAccount::new(&module.key, false, &mut module.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address: module.address,
|
||||
function_name: "main".to_string(),
|
||||
@@ -541,10 +622,11 @@ mod tests {
|
||||
LibraAccount::create_program(&module.address, &code, vec![&module.account.data]);
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
KeyedAccount::new(&module.key, false, &mut module.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address: program.address,
|
||||
function_name: "main".to_string(),
|
||||
@@ -573,10 +655,11 @@ mod tests {
|
||||
let mut payee = LibraAccount::create_unallocated();
|
||||
|
||||
let mut keyed_accounts = vec![
|
||||
KeyedAccount::new(&program.key, false, &mut program.account),
|
||||
KeyedAccount::new(&program.key, true, &mut program.account),
|
||||
KeyedAccount::new(&genesis.key, false, &mut genesis.account),
|
||||
KeyedAccount::new(&payee.key, false, &mut payee.account),
|
||||
];
|
||||
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
|
||||
let invoke_info = InvokeInfo {
|
||||
sender_address: genesis.address.clone(),
|
||||
function_name: "main".to_string(),
|
||||
|
Reference in New Issue
Block a user