Skip to content

Commit

Permalink
[functional tests] add serialization/deserialization stage
Browse files Browse the repository at this point in the history
This adds a new stage to function tests that serializes the transaction script & modules, deserializes them, and compares them to the original ones. Difference => test failure.

This can be used to ensure we implement serialization & deserialization correctly whenever we change file format.
  • Loading branch information
vgao1996 authored and calibra-opensource committed Jul 12, 2019
1 parent 0f65497 commit 04be14f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
42 changes: 39 additions & 3 deletions language/functional_tests/src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ use config::config::VMPublishingOption;
use ir_to_bytecode::{compiler::compile_program, parser::parse_program};
use std::time::Duration;
use stdlib::stdlib_modules;
use transaction_builder::transaction::make_transaction_program;
use transaction_builder::transaction::{make_transaction_program, serialize_program};
use types::{
transaction::{RawTransaction, TransactionArgument, TransactionOutput, TransactionStatus},
vm_error::{ExecutionStatus, VMStatus},
};
use vm::file_format::CompiledProgram;
use vm::{
access::ModuleAccess,
file_format::{CompiledModule, CompiledProgram, CompiledScript},
};
use vm_runtime_tests::{
account::{AccountData, AccountResource},
executor::FakeExecutor,
Expand All @@ -38,6 +41,7 @@ pub enum Stage {
// However it could be merged into the compiler.
Compiler,
Verifier,
Serializer,
Runtime,
}

Expand All @@ -48,6 +52,7 @@ impl Stage {
"parser" => Ok(Stage::Parser),
"compiler" => Ok(Stage::Compiler),
"verifier" => Ok(Stage::Verifier),
"serializer" => Ok(Stage::Serializer),
"runtime" => Ok(Stage::Runtime),
_ => Err(ErrorKind::Other(format!("unrecognized stage '{:?}'", s)).into()),
}
Expand Down Expand Up @@ -141,6 +146,33 @@ fn run_transaction(
}
}

/// Serializes the program then deserializes it.
fn run_serializer_round_trip(program: &CompiledProgram) -> Result<()> {
let (script_blob, module_blobs) = serialize_program(program)?;

assert!(module_blobs.len() == program.modules.len());

let script = CompiledScript::deserialize(&script_blob)?;
if script != program.script {
return Err(ErrorKind::Other(
"deserialized script different from original one".to_string(),
)
.into());
}

for (i, blob) in module_blobs.iter().enumerate() {
let module = CompiledModule::deserialize(blob)?;
if module != program.modules[i] {
return Err(ErrorKind::Other(format!(
"deserialized module {} different from original one",
program.modules[i].name()
))
.into());
}
}
Ok(())
}

/// Tries to unwrap the given result. Upon failure, log the error and aborts.
macro_rules! unwrap_or_log {
($res: expr, $log: expr) => {{
Expand Down Expand Up @@ -216,7 +248,11 @@ pub fn eval(config: &GlobalConfig, transactions: &[Transaction]) -> Result<Evalu
compiled_program
};

// stage 4: execute the program
// stage 4: serializer round trip
res.outputs.push(EvaluationOutput::Stage(Stage::Serializer));
unwrap_or_log!(run_serializer_round_trip(&compiled_program), res);

// stage 5: execute the program
if !transaction.config.no_execute {
res.outputs.push(EvaluationOutput::Stage(Stage::Runtime));
let txn_output = unwrap_or_log!(
Expand Down
18 changes: 12 additions & 6 deletions language/transaction_builder/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ use crate::errors::*;
use types::transaction::{Program, TransactionArgument};
use vm::file_format::CompiledProgram;

/// Creates a transaction program by serializing the the given `CompiledProgram` and
/// bundling it with transaction arguments.
pub fn make_transaction_program(
program: &CompiledProgram,
args: &[TransactionArgument],
) -> Result<Program> {
/// Serializes the given script and modules to be published.
pub fn serialize_program(program: &CompiledProgram) -> Result<(Vec<u8>, Vec<Vec<u8>>)> {
let mut script_blob = vec![];
program.script.serialize(&mut script_blob)?;

Expand All @@ -24,5 +20,15 @@ pub fn make_transaction_program(
})
.collect::<Result<Vec<_>>>()?;

Ok((script_blob, module_blobs))
}

/// Creates a transaction program by serializing the the given `CompiledProgram` and
/// bundling it with transaction arguments.
pub fn make_transaction_program(
program: &CompiledProgram,
args: &[TransactionArgument],
) -> Result<Program> {
let (script_blob, module_blobs) = serialize_program(program)?;
Ok(Program::new(script_blob, module_blobs, args.to_vec()))
}

0 comments on commit 04be14f

Please sign in to comment.