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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use parity_wasm::{
elements::{self, Deserialize},
peek_size,
};
use vm;
use wasm_utils::{self, rules};
fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set {
rules::Set::new(wasm_costs.regular, {
let mut vals = ::std::collections::BTreeMap::new();
vals.insert(
rules::InstructionType::Load,
rules::Metering::Fixed(wasm_costs.mem as u32),
);
vals.insert(
rules::InstructionType::Store,
rules::Metering::Fixed(wasm_costs.mem as u32),
);
vals.insert(
rules::InstructionType::Div,
rules::Metering::Fixed(wasm_costs.div as u32),
);
vals.insert(
rules::InstructionType::Mul,
rules::Metering::Fixed(wasm_costs.mul as u32),
);
vals
})
.with_grow_cost(wasm_costs.grow_mem)
.with_forbidden_floats()
}
pub fn payload<'a>(
params: &'a vm::ActionParams,
wasm_costs: &vm::WasmCosts,
) -> Result<(elements::Module, &'a [u8]), vm::Error> {
let code = match params.code {
Some(ref code) => &code[..],
None => {
return Err(vm::Error::Wasm("Invalid wasm call".to_owned()));
}
};
let (mut cursor, data_position) = match params.params_type {
vm::ParamsType::Embedded => {
let module_size = peek_size(&*code);
(::std::io::Cursor::new(&code[..module_size]), module_size)
}
vm::ParamsType::Separate => (::std::io::Cursor::new(&code[..]), 0),
};
let deserialized_module = elements::Module::deserialize(&mut cursor)
.map_err(|err| vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err)))?;
if deserialized_module
.memory_section()
.map_or(false, |ms| ms.entries().len() > 0)
{
return Err(vm::Error::Wasm(format!(
"Malformed wasm module: internal memory"
)));
}
let contract_module =
wasm_utils::inject_gas_counter(deserialized_module, &gas_rules(wasm_costs))
.map_err(|_| vm::Error::Wasm(format!("Wasm contract error: bytecode invalid")))?;
let contract_module =
wasm_utils::stack_height::inject_limiter(contract_module, wasm_costs.max_stack_height)
.map_err(|_| vm::Error::Wasm(format!("Wasm contract error: stack limiter failure")))?;
let data = match params.params_type {
vm::ParamsType::Embedded => {
if data_position < code.len() {
&code[data_position..]
} else {
&[]
}
}
vm::ParamsType::Separate => match params.data {
Some(ref s) => &s[..],
None => &[],
},
};
Ok((contract_module, data))
}