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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
use super::{ModuleCreator, ModuleError};
use parity_wasm::builder;
use parity_wasm::elements::{CustomSection, Module};
use byteorder::{LittleEndian, WriteBytesExt};
use rustc_hex::FromHex;
pub enum Deployer<'a> {
Memory(&'a [u8]),
CustomSection(&'a [u8]),
}
impl<'a> Deployer<'a> {
pub fn with_preset(preset: &str, payload: &'a [u8]) -> Result<Self, ()> {
match preset {
"memory" => Ok(Deployer::Memory(payload)),
"customsection" => Ok(Deployer::CustomSection(payload)),
_ => Err(()),
}
}
}
fn deployer_code() -> Vec<u8> {
FromHex::from_hex(
"
0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
657468657265756d0b676574436f646553697a65000008657468657265756d0863
6f6465436f7079000108657468657265756d0666696e6973680002030201030503
010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
4100410020001001200041046b2802002102200041046b20026b21012001200210
020b
",
)
.unwrap()
}
fn create_custom_deployer(payload: &[u8]) -> Module {
let code = deployer_code();
let mut module: Module = parity_wasm::deserialize_buffer(&code).expect("Failed to load module");
let memory_initial = (payload.len() as u32 / 65536) + 1;
let mem_type = parity_wasm::elements::MemoryType::new(memory_initial, None, false);
module.memory_section_mut().unwrap().entries_mut()[0] = mem_type;
let mut custom_payload = payload.to_vec();
custom_payload
.write_i32::<LittleEndian>(payload.len() as i32)
.unwrap();
let custom = CustomSection::new("deployer".to_string(), custom_payload);
module
.sections_mut()
.push(parity_wasm::elements::Section::Custom(custom));
module
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn create_memory_deployer(payload: &[u8]) -> Module {
let instructions = vec![
parity_wasm::elements::Instruction::I32Const(0),
parity_wasm::elements::Instruction::I32Const(payload.len() as i32),
parity_wasm::elements::Instruction::Call(0),
parity_wasm::elements::Instruction::End,
];
let memory_initial = (payload.len() as u32 / 65536) + 1;
let module = builder::module()
.function()
.signature()
.param().i32()
.param().i32()
.build()
.build()
.import()
.module("ethereum")
.field("finish")
.external()
.func(0)
.build()
.function()
.signature().build()
.body()
.with_instructions(parity_wasm::elements::Instructions::new(instructions))
.build()
.build()
.export()
.field("main")
.internal()
.func(1)
.build()
.memory()
.with_min(memory_initial)
.build()
.export()
.field("memory")
.internal()
.memory(0)
.build()
.data()
.offset(parity_wasm::elements::Instruction::I32Const(0))
.value(payload.to_vec())
.build()
.build();
module
}
impl<'a> ModuleCreator for Deployer<'a> {
fn create(&self) -> Result<Module, ModuleError> {
let output = match self {
Deployer::Memory(payload) => create_memory_deployer(&payload),
Deployer::CustomSection(payload) => create_custom_deployer(&payload),
};
Ok(output)
}
}
#[cfg(test)]
mod tests {
use super::*;
use parity_wasm;
use rustc_hex::FromHex;
#[test]
fn zero_payload() {
let payload = vec![];
let module = Deployer::with_preset("customsection", &payload)
.unwrap()
.create()
.unwrap();
let expected = FromHex::from_hex(
"
0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
657468657265756d0b676574436f646553697a65000008657468657265756d0863
6f6465436f7079000108657468657265756d0666696e6973680002030201030503
010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
4100410020001001200041046b2802002102200041046b20026b21012001200210
020b
000d086465706c6f79657200000000
",
)
.unwrap();
let output = parity_wasm::serialize(module).expect("Failed to serialize");
assert_eq!(output, expected);
}
#[test]
fn nonzero_payload() {
let payload = FromHex::from_hex("80ff007faa550011").unwrap();
let module = Deployer::with_preset("customsection", &payload)
.unwrap()
.create()
.unwrap();
let expected = FromHex::from_hex(
"
0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
657468657265756d0b676574436f646553697a65000008657468657265756d0863
6f6465436f7079000108657468657265756d0666696e6973680002030201030503
010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
4100410020001001200041046b2802002102200041046b20026b21012001200210
020b
0015086465706c6f79657280ff007faa55001108000000
",
)
.unwrap();
let output = parity_wasm::serialize(module).expect("Failed to serialize");
assert_eq!(output, expected);
}
#[test]
fn big_payload() {
let payload = [0; 632232];
let module = Deployer::with_preset("customsection", &payload)
.unwrap()
.create()
.unwrap();
let memory_initial = module.memory_section().unwrap().entries()[0]
.limits()
.initial();
assert_eq!(memory_initial, 10);
}
#[test]
fn memory_zero_payload() {
let payload = vec![];
let module = Deployer::with_preset("memory", &payload)
.unwrap()
.create()
.unwrap();
let expected = FromHex::from_hex(
"
0061736d0100000001090260027f7f0060000002130108657468657265756d0666
696e697368000003030200010503010001071102046d61696e0001066d656d6f72
7902000a0d0202000b08004100410010000b0b06010041000b00
",
)
.unwrap();
let output = parity_wasm::serialize(module).expect("Failed to serialize");
assert_eq!(output, expected);
}
#[test]
fn memory_nonzero_payload() {
let payload = FromHex::from_hex("80ff007faa550011").unwrap();
let module = Deployer::with_preset("memory", &payload)
.unwrap()
.create()
.unwrap();
let expected = FromHex::from_hex(
"
0061736d0100000001090260027f7f0060000002130108657468657265756d0666
696e697368000003030200010503010001071102046d61696e0001066d656d6f72
7902000a0d0202000b08004100410810000b0b0e010041000b0880ff007faa5500
11
",
)
.unwrap();
let output = parity_wasm::serialize(module).expect("Failed to serialize");
assert_eq!(output, expected);
}
#[test]
fn memory_big_payload() {
let payload = [0; 632232];
let module = Deployer::with_preset("memory", &payload)
.unwrap()
.create()
.unwrap();
let memory_initial = module.memory_section().unwrap().entries()[0]
.limits()
.initial();
assert_eq!(memory_initial, 10);
}
}