diff --git a/programs/move_loader_api/Cargo.toml b/programs/move_loader_api/Cargo.toml index 18ab0c5d10..0d550f29c2 100644 --- a/programs/move_loader_api/Cargo.toml +++ b/programs/move_loader_api/Cargo.toml @@ -20,16 +20,16 @@ serde_json = "1.0.40" solana-logger = { path = "../../logger", version = "0.17.0" } solana-sdk = { path = "../../sdk", version = "0.17.0" } -bytecode_verifier = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_bytecode_verifier" } -compiler = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_compiler" } -failure = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_failure_ext" } -language_e2e_tests = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3" , package = "solana_libra_language_e2e_tests" } -state_view = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_state_view" } -stdlib = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_stdlib" } -types = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_types" } -vm = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_vm" } -vm_cache_map = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_vm_cache_map" } -vm_runtime = { git = "https://github.com/solana-labs/libra", tag = "v0.0.0.3", package = "solana_libra_vm_runtime" } +bytecode_verifier = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_bytecode_verifier" } +compiler = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_compiler" } +failure = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_failure_ext" } +language_e2e_tests = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_language_e2e_tests" } +state_view = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_state_view" } +stdlib = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_stdlib" } +types = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_types" } +vm = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_vm" } +vm_cache_map = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_vm_cache_map" } +vm_runtime = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_vm_runtime" } [lib] crate-type = ["lib"] diff --git a/programs/move_loader_api/src/account_state.rs b/programs/move_loader_api/src/account_state.rs index 688939d339..53ea364910 100644 --- a/programs/move_loader_api/src/account_state.rs +++ b/programs/move_loader_api/src/account_state.rs @@ -8,7 +8,6 @@ use stdlib::stdlib_modules; use types::{ account_address::AccountAddress, byte_array::ByteArray, - transaction::Program, write_set::{WriteOp, WriteSet}, }; use vm::{ @@ -38,8 +37,16 @@ fn to_array_32(array: &[u8]) -> &[u8; 32] { pub enum LibraAccountState { /// No data for this account yet Unallocated, - /// Program bits - Program(Program), + /// Serialized compiled program bytes + CompiledProgram { + script_bytes: Vec, + modules_bytes: Vec>, + }, + /// Serialized verified program bytes + VerifiedProgram { + script_bytes: Vec, + modules_bytes: Vec>, + }, /// Write set containing a Libra account's data User(WriteSet), /// Write sets containing the mint and stdlib modules @@ -80,20 +87,23 @@ impl LibraAccountState { }; let compiled_program = compiler.into_compiled_program().expect("Failed to compile"); - let mut script = vec![]; + let mut script_bytes = vec![]; compiled_program .script - .serialize(&mut script) + .serialize(&mut script_bytes) .expect("Unable to serialize script"); - let mut modules = vec![]; + let mut modules_bytes = vec![]; for module in compiled_program.modules.iter() { let mut buf = vec![]; module .serialize(&mut buf) .expect("Unable to serialize module"); - modules.push(buf); + modules_bytes.push(buf); + } + LibraAccountState::CompiledProgram { + script_bytes, + modules_bytes, } - LibraAccountState::Program(Program::new(script, modules, vec![])) } pub fn create_user(write_set: WriteSet) -> Self { diff --git a/programs/move_loader_api/src/data_store.rs b/programs/move_loader_api/src/data_store.rs index 2812bd2c16..c478d58d43 100644 --- a/programs/move_loader_api/src/data_store.rs +++ b/programs/move_loader_api/src/data_store.rs @@ -207,4 +207,4 @@ mod tests { assert_eq!(&before2, after2); assert_eq!(&before3, after3); } -} \ No newline at end of file +} diff --git a/programs/move_loader_api/src/processor.rs b/programs/move_loader_api/src/processor.rs index 373bac3122..caa0e40826 100644 --- a/programs/move_loader_api/src/processor.rs +++ b/programs/move_loader_api/src/processor.rs @@ -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, - ) -> InstructionError { - debug!("Error: Script verification failed: {:?}", err); - InstructionError::InvalidInstructionData - } #[allow(clippy::needless_pass_by_value)] fn map_data_error(err: std::boxed::Box) -> InstructionError { debug!("Error: Account data: {:?}", err); InstructionError::InvalidAccountData } + fn map_vm_verification_error( + err: (CompiledModule, Vec), + ) -> 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), 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), 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), 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::, _>>() + .map_err(Self::map_vm_binary_error)?; + + Ok((script, modules)) + } + + fn deserialize_verified_program( + data: &[u8], + ) -> Result<(VerifiedScript, Vec), 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::, _>>() + .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::, _>>() + .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(),