1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
pub mod wasm_costs;
use std::fmt::{self, Display, Formatter};
use parity_wasm::elements::{self, Module};
use pwasm_utils::{self, stack_height};
use crate::wasm_costs::WasmCosts;
pub const MEM_PAGES: u32 = 64;
#[derive(Debug)]
pub enum PreprocessingError {
Deserialize(String),
OperationForbiddenByGasRules,
StackLimiter,
}
impl From<elements::Error> for PreprocessingError {
fn from(error: elements::Error) -> Self {
PreprocessingError::Deserialize(error.to_string())
}
}
impl Display for PreprocessingError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
PreprocessingError::Deserialize(error) => write!(f, "Deserialization error: {}", error),
PreprocessingError::OperationForbiddenByGasRules => write!(f, "Encountered operation forbidden by gas rules. Consult instruction -> metering config map"),
PreprocessingError::StackLimiter => write!(f, "Stack limiter error"),
}
}
}
pub struct Preprocessor {
wasm_costs: WasmCosts,
mem_pages: u32,
}
impl Preprocessor {
pub fn new(wasm_costs: WasmCosts) -> Self {
Self {
wasm_costs,
mem_pages: MEM_PAGES,
}
}
pub fn preprocess(&self, module_bytes: &[u8]) -> Result<Module, PreprocessingError> {
let module = deserialize(module_bytes)?;
let module = pwasm_utils::externalize_mem(module, None, self.mem_pages);
let module = pwasm_utils::inject_gas_counter(module, &self.wasm_costs.to_set())
.map_err(|_| PreprocessingError::OperationForbiddenByGasRules)?;
let module = stack_height::inject_limiter(module, self.wasm_costs.max_stack_height)
.map_err(|_| PreprocessingError::StackLimiter)?;
Ok(module)
}
}
pub fn deserialize(module_bytes: &[u8]) -> Result<Module, PreprocessingError> {
parity_wasm::deserialize_buffer::<Module>(module_bytes).map_err(Into::into)
}