owasm-utils-cli 0.6.1

Collection of command-line utilities and corresponding Rust API for producing owasm-compatible executables
Documentation
extern crate parity_wasm;
extern crate owasm_utils as utils;
extern crate owasm_utils_cli as logger;
extern crate clap;

use clap::{App, Arg};
use parity_wasm::elements;

fn fail(msg: &str) -> ! {
    eprintln!("{}", msg);
    std::process::exit(1)
}

const ALLOWED_IMPORTS: &'static [&'static str] = &[
    "ret",
    "storage_read",
    "storage_write",
    "balance",
    "sender",
    "origin",
    "fetch_input",
    "input_length",
    "ccall",
    "dcall",
    "scall",
    "create",
    "balance",
    "blockhash",
    "blocknumber",
    "coinbase",
    "timestamp",
    "difficulty",
    "gaslimit",
    "address",
    "value",
    "suicide",
    "panic",
    "elog",
    "abort"
];

fn main() {
    logger::init_log();

    let matches = App::new("wasm-check")
                        .arg(Arg::with_name("input")
                            .index(1)
                            .required(true)
                            .help("Input WASM file"))
                        .get_matches();

    let input = matches.value_of("input").expect("is required; qed");

    let module = parity_wasm::deserialize_file(&input).expect("Input module deserialization failed");

    for section in module.sections() {
        match *section {
            elements::Section::Import(ref import_section) => {
                let mut has_imported_memory_properly_named = false;
                for entry in import_section.entries() {
                    if entry.module() != "env" {
                        fail("All imports should be from env");
                    }
                    match *entry.external() {
                        elements::External::Function(_) => {
                            if !ALLOWED_IMPORTS.contains(&entry.field()) {
                                fail(&format!("'{}' is not supported by the runtime", entry.field()));
                            }
                        },
                        elements::External::Memory(m) => {
                            if entry.field() == "memory" {
                                has_imported_memory_properly_named = true;
                            }

                            let max = if let Some(max) = m.limits().maximum() {
                                max
                            } else {
                                fail("There is a limit on memory in Parity runtime, and this program does not limit memory");
                            };

                            if max > 16 {
                                fail(&format!(
                                    "Parity runtime has 1Mb limit (16 pages) on max contract memory, this program speicifies {}",
                                    max
                                ));
                            }
                        },
                        elements::External::Global(_) => {
                            fail("Parity runtime does not provide any globals")
                        },
                        _ => { continue; }
                    }
                }

                if !has_imported_memory_properly_named {
                    fail("No imported memory from env::memory in the contract");
                }
            }
            _ => { continue; }
        }
    }
}