1use parity_wasm::builder;
2use parity_wasm::elements::{CustomSection, Module};
3
4use super::{ChiselModule, ModuleError, ModuleKind, ModulePreset, ModuleTranslator};
5
6pub enum Deployer {
8 Memory,
9 CustomSection,
10}
11
12impl<'a> ChiselModule<'a> for Deployer {
13 type ObjectReference = &'a dyn ModuleTranslator;
14
15 fn id(&'a self) -> String {
16 "deployer".to_string()
17 }
18
19 fn kind(&'a self) -> ModuleKind {
20 ModuleKind::Translator
21 }
22
23 fn as_abstract(&'a self) -> Self::ObjectReference {
24 self as Self::ObjectReference
25 }
26}
27
28impl ModulePreset for Deployer {
29 fn with_preset(preset: &str) -> Result<Self, ModuleError> {
30 match preset {
31 "memory" => Ok(Deployer::Memory),
32 "customsection" => Ok(Deployer::CustomSection),
33 _ => Err(ModuleError::NotSupported),
34 }
35 }
36}
37
38fn deployer_code() -> Vec<u8> {
68 vec![
69 0, 97, 115, 109, 1, 0, 0, 0, 1, 19, 4, 96, 0, 1, 127, 96, 3, 127, 127, 127, 0, 96, 2, 127,
70 127, 0, 96, 0, 0, 2, 62, 3, 8, 101, 116, 104, 101, 114, 101, 117, 109, 11, 103, 101, 116,
71 67, 111, 100, 101, 83, 105, 122, 101, 0, 0, 8, 101, 116, 104, 101, 114, 101, 117, 109, 8,
72 99, 111, 100, 101, 67, 111, 112, 121, 0, 1, 8, 101, 116, 104, 101, 114, 101, 117, 109, 6,
73 102, 105, 110, 105, 115, 104, 0, 2, 3, 2, 1, 3, 5, 3, 1, 0, 1, 7, 17, 2, 6, 109, 101, 109,
74 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 3, 10, 44, 1, 42, 1, 3, 127, 16, 0, 33, 0,
75 65, 0, 65, 0, 32, 0, 16, 1, 32, 0, 65, 4, 107, 40, 2, 0, 33, 2, 32, 0, 65, 4, 107, 32, 2,
76 107, 33, 1, 32, 1, 32, 2, 16, 2, 11,
77 ]
78}
79
80fn create_custom_deployer(payload: &[u8]) -> Result<Module, ModuleError> {
82 let code = deployer_code();
85
86 let mut module = Module::from_bytes(&code)?;
88
89 let memory_initial = (payload.len() as u32 / 65536) + 1;
91 let mem_type = parity_wasm::elements::MemoryType::new(memory_initial, None);
92 module
93 .memory_section_mut()
94 .expect("failed to get memory section")
96 .entries_mut()[0] = mem_type;
97
98 let payload_len = payload.len() as u32;
100 let payload_len = payload_len.to_le_bytes();
101 let mut custom_payload = payload.to_vec();
102 custom_payload.extend_from_slice(&payload_len);
103
104 let custom = CustomSection::new("deployer".to_string(), custom_payload);
106
107 module
108 .sections_mut()
109 .push(parity_wasm::elements::Section::Custom(custom));
110
111 Ok(module)
112}
113
114#[rustfmt::skip]
116fn create_memory_deployer(payload: &[u8]) -> Module {
117 let instructions = vec![
119 parity_wasm::elements::Instruction::I32Const(0),
120 parity_wasm::elements::Instruction::I32Const(payload.len() as i32),
121 parity_wasm::elements::Instruction::Call(0),
122 parity_wasm::elements::Instruction::End,
123 ];
124
125 let memory_initial = (payload.len() as u32 / 65536) + 1;
126
127 builder::module()
128 .function()
130 .signature()
131 .param().i32()
132 .param().i32()
133 .build()
134 .build()
135 .import()
136 .module("ethereum")
137 .field("finish")
138 .external()
139 .func(0)
140 .build()
141 .function()
143 .signature().build()
145 .body()
146 .with_instructions(parity_wasm::elements::Instructions::new(instructions))
147 .build()
148 .build()
149 .export()
151 .field("main")
152 .internal()
153 .func(2)
154 .build()
155 .memory()
157 .with_min(memory_initial)
158 .build()
159 .export()
161 .field("memory")
162 .internal()
163 .memory(0)
164 .build()
165 .data()
167 .offset(parity_wasm::elements::Instruction::I32Const(0))
168 .value(payload.to_vec())
169 .build()
170 .build()
171}
172
173impl ModuleTranslator for Deployer {
174 fn translate_inplace(&self, _module: &mut Module) -> Result<bool, ModuleError> {
175 Err(ModuleError::NotSupported)
176 }
177
178 fn translate(&self, module: &Module) -> Result<Option<Module>, ModuleError> {
179 let payload = module.clone().to_bytes()?;
180 let output = match self {
181 Deployer::Memory => create_memory_deployer(&payload),
182 Deployer::CustomSection => create_custom_deployer(&payload)?,
183 };
184 Ok(Some(output))
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use rustc_hex::FromHex;
191
192 use super::*;
193
194 #[test]
195 fn zero_payload() {
196 let payload = vec![];
197 let output = create_custom_deployer(&payload)
198 .unwrap()
199 .to_bytes()
200 .unwrap();
201 let expected = FromHex::from_hex(
202 "
203 0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
204 657468657265756d0b676574436f646553697a65000008657468657265756d0863
205 6f6465436f7079000108657468657265756d0666696e6973680002030201030503
206 010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
207 4100410020001001200041046b2802002102200041046b20026b21012001200210
208 020b
209
210 000d086465706c6f79657200000000
211 ",
212 )
213 .unwrap();
214 assert_eq!(output, expected);
215 }
216
217 #[test]
218 fn nonzero_payload() {
219 let payload = FromHex::from_hex("80ff007faa550011").unwrap();
220 let output = create_custom_deployer(&payload)
221 .unwrap()
222 .to_bytes()
223 .unwrap();
224 let expected = FromHex::from_hex(
225 "
226 0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
227 657468657265756d0b676574436f646553697a65000008657468657265756d0863
228 6f6465436f7079000108657468657265756d0666696e6973680002030201030503
229 010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
230 4100410020001001200041046b2802002102200041046b20026b21012001200210
231 020b
232
233 0015086465706c6f79657280ff007faa55001108000000
234 ",
235 )
236 .unwrap();
237 assert_eq!(output, expected);
238 }
239
240 #[test]
241 fn big_payload() {
242 let payload = [0; 632232];
243 let module = create_custom_deployer(&payload).unwrap();
244 let memory_initial = module.memory_section().unwrap().entries()[0]
245 .limits()
246 .initial();
247 assert_eq!(memory_initial, 10);
248 }
249
250 #[test]
251 fn memory_zero_payload() {
252 let payload = vec![];
253 let output = create_memory_deployer(&payload).to_bytes().unwrap();
254 let expected = FromHex::from_hex(
255 "
256 0061736d0100000001090260027f7f0060000002130108657468657265756d0666
257 696e697368000003030200010503010001071102046d61696e0002066d656d6f72
258 7902000a0d0202000b08004100410010000b0b06010041000b00
259 ",
260 )
261 .unwrap();
262 assert_eq!(output, expected);
263 }
264
265 #[test]
266 fn memory_nonzero_payload() {
267 let payload = FromHex::from_hex("80ff007faa550011").unwrap();
268 let output = create_memory_deployer(&payload).to_bytes().unwrap();
269 let expected = FromHex::from_hex(
270 "
271 0061736d0100000001090260027f7f0060000002130108657468657265756d0666
272 696e697368000003030200010503010001071102046d61696e0002066d656d6f72
273 7902000a0d0202000b08004100410810000b0b0e010041000b0880ff007faa5500
274 11
275 ",
276 )
277 .unwrap();
278 assert_eq!(output, expected);
279 }
280
281 #[test]
282 fn memory_big_payload() {
283 let payload = [0; 632232];
284 let module = create_memory_deployer(&payload);
285 let memory_initial = module.memory_section().unwrap().entries()[0]
286 .limits()
287 .initial();
288 assert_eq!(memory_initial, 10);
289 }
290
291 #[test]
292 fn customsection_interface_test() {
293 let payload = Module::default();
294 let module = Deployer::with_preset("customsection")
295 .unwrap()
296 .translate(&payload)
297 .unwrap()
298 .unwrap();
299 let expected = FromHex::from_hex(
300 "
301 0061736d010000000113046000017f60037f7f7f0060027f7f00600000023e0308
302 657468657265756d0b676574436f646553697a65000008657468657265756d0863
303 6f6465436f7079000108657468657265756d0666696e6973680002030201030503
304 010001071102066d656d6f72790200046d61696e00030a2c012a01037f10002100
305 4100410020001001200041046b2802002102200041046b20026b21012001200210
306 020b0015086465706c6f7965720061736d0100000008000000
307 ",
308 )
309 .unwrap();
310 let output = module.to_bytes().unwrap();
311 assert_eq!(output, expected);
312 }
313
314 #[test]
315 fn memory_interface_test() {
316 let payload = Module::default();
317 let module = Deployer::with_preset("memory")
318 .unwrap()
319 .translate(&payload)
320 .unwrap()
321 .unwrap();
322 let expected = FromHex::from_hex(
323 "
324 0061736d0100000001090260027f7f0060000002130108657468657265756d0666
325 696e697368000003030200010503010001071102046d61696e0002066d656d6f72
326 7902000a0d0202000b08004100410810000b0b0e010041000b080061736d010000
327 00
328 ",
329 )
330 .unwrap();
331 let output = module.to_bytes().unwrap();
332 assert_eq!(output, expected);
333 }
334}