pwasm-utils 0.18.2

Collection of command-line utilities and corresponding Rust api for producing pwasm-compatible executables
Documentation
use clap::{App, Arg};
use parity_wasm::elements;
use pwasm_utils::logger;

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

const ALLOWED_IMPORTS: &[&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();

	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(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,
		}
	}
}