vapcore_wasm/
parser.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Tetsy Vapory.
3
4// Tetsy Vapory is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Tetsy Vapory is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Tetsy Vapory.  If not, see <http://www.gnu.org/licenses/>.
16
17//! ActionParams parser for wasm
18
19use tetsy_vm;
20use wasm_utils::{self, rules};
21use tetsy_wasm::elements::{self, Deserialize};
22use tetsy_wasm::peek_size;
23
24fn gas_rules(wasm_costs: &tetsy_vm::WasmCosts) -> rules::Set {
25	rules::Set::new(
26		wasm_costs.regular,
27		{
28			let mut vals = ::std::collections::BTreeMap::new();
29			vals.insert(rules::InstructionType::Load, rules::Metering::Fixed(wasm_costs.mem as u32));
30			vals.insert(rules::InstructionType::Store, rules::Metering::Fixed(wasm_costs.mem as u32));
31			vals.insert(rules::InstructionType::Div, rules::Metering::Fixed(wasm_costs.div as u32));
32			vals.insert(rules::InstructionType::Mul, rules::Metering::Fixed(wasm_costs.mul as u32));
33			vals
34		})
35		.with_grow_cost(wasm_costs.grow_mem)
36		.with_forbidden_floats()
37}
38
39/// Splits payload to code and data according to params.params_type, also
40/// loads the module instance from payload and injects gas counter according
41/// to schedule.
42pub fn payload<'a>(params: &'a tetsy_vm::ActionParams, wasm_costs: &tetsy_vm::WasmCosts)
43	-> Result<(elements::Module, &'a [u8]), tetsy_vm::Error>
44{
45	let code = match params.code {
46		Some(ref code) => &code[..],
47		None => { return Err(tetsy_vm::Error::Wasm("Invalid wasm call".to_owned())); }
48	};
49
50	let (mut cursor, data_position) = match params.params_type {
51		tetsy_vm::ParamsType::Embedded => {
52			let module_size = peek_size(&*code);
53			(
54				::std::io::Cursor::new(&code[..module_size]),
55				module_size
56			)
57		},
58		tetsy_vm::ParamsType::Separate => {
59			(::std::io::Cursor::new(&code[..]), 0)
60		},
61	};
62
63	let deserialized_module = elements::Module::deserialize(
64			&mut cursor
65		).map_err(|err| {
66			tetsy_vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
67		})?;
68
69	if deserialized_module.memory_section().map_or(false, |ms| ms.entries().len() > 0) {
70		// According to WebAssembly spec, internal memory is hidden from embedder and should not
71		// be interacted with. So we disable this kind of modules at decoding level.
72		return Err(tetsy_vm::Error::Wasm(format!("Malformed wasm module: internal memory")));
73	}
74
75	let contract_module = wasm_utils::inject_gas_counter(
76		deserialized_module,
77		&gas_rules(wasm_costs),
78	).map_err(|_| tetsy_vm::Error::Wasm(format!("Wasm contract error: bytecode invalid")))?;
79
80	let contract_module = wasm_utils::stack_height::inject_limiter(
81		contract_module,
82		wasm_costs.max_stack_height,
83	).map_err(|_| tetsy_vm::Error::Wasm(format!("Wasm contract error: stack limiter failure")))?;
84
85	let data = match params.params_type {
86		tetsy_vm::ParamsType::Embedded => {
87			if data_position < code.len() { &code[data_position..] } else { &[] }
88		},
89		tetsy_vm::ParamsType::Separate => {
90			match params.data {
91				Some(ref s) => &s[..],
92				None => &[]
93			}
94		}
95	};
96
97	Ok((contract_module, data))
98}