Move verify to finalize (#5297)

automerge
This commit is contained in:
Jack May
2019-07-26 17:51:07 -07:00
committed by Grimes
parent 9d34b80ed6
commit e2c9d87d91
4 changed files with 157 additions and 64 deletions

View File

@ -20,16 +20,16 @@ serde_json = "1.0.40"
solana-logger = { path = "../../logger", version = "0.17.0" } solana-logger = { path = "../../logger", version = "0.17.0" }
solana-sdk = { path = "../../sdk", 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" } 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", tag = "v0.0.0.3", package = "solana_libra_compiler" } 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", tag = "v0.0.0.3", package = "solana_libra_failure_ext" } 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", tag = "v0.0.0.3" , package = "solana_libra_language_e2e_tests" } 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", tag = "v0.0.0.3", package = "solana_libra_state_view" } 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", tag = "v0.0.0.3", package = "solana_libra_stdlib" } 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", tag = "v0.0.0.3", package = "solana_libra_types" } 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", tag = "v0.0.0.3", package = "solana_libra_vm" } 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", tag = "v0.0.0.3", package = "solana_libra_vm_cache_map" } 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", tag = "v0.0.0.3", package = "solana_libra_vm_runtime" } vm_runtime = { git = "https://github.com/solana-labs/libra", branch = "solana-0.0.0.3.1", package = "solana_libra_vm_runtime" }
[lib] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@ -8,7 +8,6 @@ use stdlib::stdlib_modules;
use types::{ use types::{
account_address::AccountAddress, account_address::AccountAddress,
byte_array::ByteArray, byte_array::ByteArray,
transaction::Program,
write_set::{WriteOp, WriteSet}, write_set::{WriteOp, WriteSet},
}; };
use vm::{ use vm::{
@ -38,8 +37,16 @@ fn to_array_32(array: &[u8]) -> &[u8; 32] {
pub enum LibraAccountState { pub enum LibraAccountState {
/// No data for this account yet /// No data for this account yet
Unallocated, Unallocated,
/// Program bits /// Serialized compiled program bytes
Program(Program), 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 /// Write set containing a Libra account's data
User(WriteSet), User(WriteSet),
/// Write sets containing the mint and stdlib modules /// 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 compiled_program = compiler.into_compiled_program().expect("Failed to compile");
let mut script = vec![]; let mut script_bytes = vec![];
compiled_program compiled_program
.script .script
.serialize(&mut script) .serialize(&mut script_bytes)
.expect("Unable to serialize script"); .expect("Unable to serialize script");
let mut modules = vec![]; let mut modules_bytes = vec![];
for module in compiled_program.modules.iter() { for module in compiled_program.modules.iter() {
let mut buf = vec![]; let mut buf = vec![];
module module
.serialize(&mut buf) .serialize(&mut buf)
.expect("Unable to serialize module"); .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 { pub fn create_user(write_set: WriteSet) -> Self {

View File

@ -207,4 +207,4 @@ mod tests {
assert_eq!(&before2, after2); assert_eq!(&before2, after2);
assert_eq!(&before3, after3); assert_eq!(&before3, after3);
} }
} }

View File

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