diff --git a/build/main.rs b/build/main.rs index ede2bd0..5bf79d8 100644 --- a/build/main.rs +++ b/build/main.rs @@ -19,9 +19,11 @@ use utils::{CREATE_SYMBOL, CALL_SYMBOL, ununderscore_funcs, externalize_mem, shr #[derive(Debug)] pub enum Error { Io(io::Error), - NoSuitableFile(String), - TooManyFiles(String), - NoEnvVar, + FailedToCopy(String), + Decoding(elements::Error, String), + Encoding(elements::Error), + Packing(utils::PackingError), + Optimizer, } impl From for Error { @@ -30,6 +32,32 @@ impl From for Error { } } +impl From for Error { + fn from(_err: utils::OptimizerError) -> Self { + Error::Optimizer + } +} + +impl From for Error { + fn from(err: utils::PackingError) -> Self { + Error::Packing(err) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + use Error::*; + match *self { + Io(ref io) => write!(f, "Generic i/o error: {}", io), + FailedToCopy(ref msg) => write!(f, "{}. Have you tried to run \"cargo build\"?", msg), + Decoding(ref err, ref file) => write!(f, "Decoding error ({}). Must be a valid wasm file {}. Pointed wrong file?", err, file), + Encoding(ref err) => write!(f, "Encoding error ({}). Almost impossible to happen, no free disk space?", err), + Optimizer => write!(f, "Optimization error due to missing export section. Pointed wrong file?"), + Packing(ref e) => write!(f, "Packing failed due to module structure error: {}. Sure used correct libraries for building contracts?", e), + } + } +} + pub fn wasm_path(input: &source::SourceInput) -> String { let mut path = PathBuf::from(input.target_dir()); path.push(format!("{}.wasm", input.final_name())); @@ -50,7 +78,10 @@ pub fn process_output(input: &source::SourceInput) -> Result<(), Error> { let mut target_path = PathBuf::from(input.target_dir()); target_path.push(format!("{}.wasm", input.final_name())); - fs::copy(cargo_path, target_path)?; + fs::copy(cargo_path.as_path(), target_path.as_path()) + .map_err(|io| Error::FailedToCopy( + format!("Failed to copy '{}' to '{}': {}", cargo_path.display(), target_path.display(), io) + ))?; Ok(()) } @@ -63,7 +94,7 @@ fn has_ctor(module: &elements::Module) -> bool { } } -fn main() { +fn do_main() -> Result<(), Error> { utils::init_log(); let matches = App::new("wasm-build") @@ -117,7 +148,7 @@ fn main() { } else if source_target_val == source::EMSCRIPTEN_TRIPLET { source_input = source_input.emscripten() } else { - println!("--target can be: '{}' or '{}'", source::EMSCRIPTEN_TRIPLET, source::UNKNOWN_TRIPLET); + eprintln!("--target can be: '{}' or '{}'", source::EMSCRIPTEN_TRIPLET, source::UNKNOWN_TRIPLET); ::std::process::exit(1); } @@ -125,11 +156,12 @@ fn main() { source_input = source_input.with_final(final_name); } - process_output(&source_input).expect("Failed to process cargo target directory"); + process_output(&source_input)?; let path = wasm_path(&source_input); - let mut module = parity_wasm::deserialize_file(&path).unwrap(); + let mut module = parity_wasm::deserialize_file(&path) + .map_err(|e| Error::Decoding(e, path.to_string()))?; if let source::SourceTarget::Emscripten = source_input.target() { module = ununderscore_funcs(module); @@ -166,28 +198,36 @@ fn main() { utils::optimize( &mut module, vec![CALL_SYMBOL] - ).expect("Optimizer to finish without errors"); + )?; } if let Some(save_raw_path) = matches.value_of("save_raw") { - parity_wasm::serialize_to_file(save_raw_path, module.clone()) - .expect("Failed to write intermediate module"); + parity_wasm::serialize_to_file(save_raw_path, module.clone()).map_err(Error::Encoding)?; } - let raw_module = parity_wasm::serialize(module).expect("Failed to serialize module"); + let raw_module = parity_wasm::serialize(module).map_err(Error::Encoding)?; // If module has an exported function with name=CREATE_SYMBOL // build will pack the module (raw_module) into this funciton and export as CALL_SYMBOL. // Otherwise it will just save an optimised raw_module if has_ctor(&ctor_module) { if !matches.is_present("skip_optimization") { - utils::optimize(&mut ctor_module, vec![CREATE_SYMBOL]).expect("Optimizer to finish without errors"); + utils::optimize(&mut ctor_module, vec![CREATE_SYMBOL])?; } - let ctor_module = utils::pack_instance(raw_module, ctor_module).expect("Packing failed"); - parity_wasm::serialize_to_file(&path, ctor_module).expect("Failed to serialize to file"); + let ctor_module = utils::pack_instance(raw_module, ctor_module)?; + parity_wasm::serialize_to_file(&path, ctor_module).map_err(Error::Encoding)?; } else { - let mut file = fs::File::create(&path).expect("Failed to create file"); - file.write_all(&raw_module).expect("Failed to write module to file"); + let mut file = fs::File::create(&path)?; + file.write_all(&raw_module)?; + } + + Ok(()) +} + +fn main() { + if let Err(e) = do_main() { + eprintln!("{}", e); + std::process::exit(1) } } diff --git a/src/lib.rs b/src/lib.rs index 5e3aec5..8753ec7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,5 +24,5 @@ pub use optimizer::{optimize, Error as OptimizerError}; pub use gas::inject_gas_counter; pub use logger::init_log; pub use ext::{externalize, externalize_mem, underscore_funcs, ununderscore_funcs, shrink_unknown_stack}; -pub use pack::pack_instance; +pub use pack::{pack_instance, Error as PackingError}; pub use runtime_type::inject_runtime_type; diff --git a/src/pack.rs b/src/pack.rs index 9fa66f8..1906dbd 100644 --- a/src/pack.rs +++ b/src/pack.rs @@ -1,3 +1,4 @@ +use std::fmt; use parity_wasm::elements::{ self, Section, Opcode, DataSegment, InitExpr, Internal, External, ImportCountType, @@ -19,10 +20,24 @@ pub enum Error { InvalidCreateSignature, NoCreateSymbol, InvalidCreateMember, - NoRetImported, NoImportSection, } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::MalformedModule => write!(f, "Module internal references are inconsistent"), + Error::NoTypeSection => write!(f, "No type section in the module"), + Error::NoExportSection => write!(f, "No export section in the module"), + Error::NoCodeSection => write!(f, "No code section inthe module"), + Error::InvalidCreateSignature => write!(f, "Exported symbol `deploy` has invalid signature, should be () -> ()"), + Error::InvalidCreateMember => write!(f, "Exported symbol `deploy` should be a function"), + Error::NoCreateSymbol => write!(f, "No exported `deploy` symbol"), + Error::NoImportSection => write!(f, "No import section in the module"), + } + } +} + /// If module has an exported "_create" function we want to pack it into "constructor". /// `raw_module` is the actual contract code /// `ctor_module` is the constructor which should return `raw_module`