| @@ -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"] | ||||
|   | ||||
| @@ -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<u8>, | ||||
|         modules_bytes: Vec<Vec<u8>>, | ||||
|     }, | ||||
|     /// Serialized verified program bytes | ||||
|     VerifiedProgram { | ||||
|         script_bytes: Vec<u8>, | ||||
|         modules_bytes: Vec<Vec<u8>>, | ||||
|     }, | ||||
|     /// 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 { | ||||
|   | ||||
| @@ -207,4 +207,4 @@ mod tests { | ||||
|         assert_eq!(&before2, after2); | ||||
|         assert_eq!(&before3, after3); | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -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