use serde_json;
use solana_libra_bytecode_verifier::{
verifier::{verify_module_dependencies, VerifiedProgram},
VerifiedModule,
};
use solana_libra_compiler::{util, Compiler};
use solana_libra_ir_to_bytecode::parser::{parse_module, parse_script};
use solana_libra_stdlib::stdlib_modules;
use solana_libra_types::{
access_path::AccessPath,
account_address::AccountAddress,
transaction::{Module, Script},
vm_error::VMStatus,
};
use solana_libra_vm::file_format::CompiledModule;
use std::{
convert::TryFrom,
fs,
io::Write,
path::{Path, PathBuf},
};
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(name = "IR Compiler", about = "Move IR to bytecode compiler.")]
struct Args {
#[structopt(short = "m", long = "module")]
pub module_input: bool,
#[structopt(short = "a", long = "address")]
pub address: Option<String>,
#[structopt(long = "no-stdlib")]
pub no_stdlib: bool,
#[structopt(long = "no-verify")]
pub no_verify: bool,
#[structopt(parse(from_os_str))]
pub source_path: PathBuf,
#[structopt(short = "-l", long = "list-dependencies")]
pub list_dependencies: bool,
#[structopt(long = "deps")]
pub deps_path: Option<String>,
}
fn print_errors_and_exit(verification_errors: &[VMStatus]) -> ! {
println!("Verification failed. Errors below:");
for e in verification_errors {
println!("{:?}", e);
}
std::process::exit(1);
}
fn do_verify_module(module: CompiledModule, dependencies: &[VerifiedModule]) -> VerifiedModule {
let verified_module =
VerifiedModule::new(module).unwrap_or_else(|(_, errors)| print_errors_and_exit(&errors));
let errors = verify_module_dependencies(&verified_module, dependencies);
if !errors.is_empty() {
print_errors_and_exit(&errors);
}
verified_module
}
fn write_output(path: &PathBuf, buf: &[u8]) {
let mut f = fs::File::create(path)
.unwrap_or_else(|err| panic!("Unable to open output file {:?}: {}", path, err));
f.write_all(&buf)
.unwrap_or_else(|err| panic!("Unable to write to output file {:?}: {}", path, err));
}
fn main() {
let args = Args::from_args();
let address = args
.address
.map(|a| AccountAddress::try_from(a).unwrap())
.unwrap_or_else(AccountAddress::default);
let source_path = Path::new(&args.source_path);
let mvir_extension = "mvir";
let mv_extension = "mv";
let extension = source_path
.extension()
.expect("Missing file extension for input source file");
if extension != mvir_extension {
println!(
"Bad source file extension {:?}; expected {}",
extension, mvir_extension
);
std::process::exit(1);
}
if args.list_dependencies {
let source = fs::read_to_string(args.source_path.clone()).expect("Unable to read file");
let dependency_list: Vec<AccessPath> = if args.module_input {
let module = parse_module(&source).expect("Unable to parse module");
module.get_external_deps()
} else {
let script = parse_script(&source).expect("Unable to parse module");
script.get_external_deps()
}
.into_iter()
.map(|m| AccessPath::code_access_path(&m))
.collect();
println!(
"{}",
serde_json::to_string(&dependency_list).expect("Unable to serialize dependencies")
);
return;
}
let deps = {
if let Some(path) = args.deps_path {
let deps = fs::read_to_string(path).expect("Unable to read dependency file");
let deps_list: Vec<Vec<u8>> =
serde_json::from_str(deps.as_str()).expect("Unable to parse dependency file");
deps_list
.into_iter()
.map(|module_bytes| {
VerifiedModule::new(
CompiledModule::deserialize(module_bytes.as_slice())
.expect("Downloaded module blob can't be deserialized"),
)
.expect("Downloaded module blob failed verifier")
})
.collect()
} else if args.no_stdlib {
vec![]
} else {
stdlib_modules().to_vec()
}
};
if !args.module_input {
let source = fs::read_to_string(args.source_path.clone()).expect("Unable to read file");
let compiler = Compiler {
address,
skip_stdlib_deps: args.no_stdlib,
extra_deps: deps,
..Compiler::default()
};
let (compiled_program, dependencies) = compiler
.into_compiled_program_and_deps(&source)
.expect("Failed to compile program");
let compiled_program = if !args.no_verify {
let verified_program = VerifiedProgram::new(compiled_program, &dependencies)
.expect("Failed to verify program");
verified_program.into_inner()
} else {
compiled_program
};
let mut script = vec![];
compiled_program
.script
.serialize(&mut script)
.expect("Unable to serialize script");
let payload = Script::new(script, vec![]);
let payload_bytes = serde_json::to_vec(&payload).expect("Unable to serialize program");
write_output(&source_path.with_extension(mv_extension), &payload_bytes);
} else {
let compiled_module = util::do_compile_module(&args.source_path, address, &deps);
let compiled_module = if !args.no_verify {
let verified_module = do_verify_module(compiled_module, &deps);
verified_module.into_inner()
} else {
compiled_module
};
let mut module = vec![];
compiled_module
.serialize(&mut module)
.expect("Unable to serialize module");
let payload = Module::new(module);
let payload_bytes = serde_json::to_vec(&payload).expect("Unable to serialize program");
write_output(&source_path.with_extension(mv_extension), &payload_bytes);
}
}