libchisel/
deployer.rs

1use parity_wasm::builder;
2use parity_wasm::elements::{CustomSection, Module};
3
4use super::{ChiselModule, ModuleError, ModuleKind, ModulePreset, ModuleTranslator};
5
6/// Enum on which ModuleTranslator is implemented.
7pub 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
38/*
39(module
40  (import "ethereum" "getCodeSize" (func $getCodeSize (result i32)))
41  (import "ethereum" "codeCopy" (func $codeCopy (param i32 i32 i32)))
42  (import "ethereum" "finish" (func $finish (param i32 i32)))
43  (memory 1)
44  (export "memory" (memory 0))
45  (export "main" (func $main))
46  (func $main
47    ;; load total code size
48    (local $size i32)
49    (local $payload_offset i32)
50    (local $payload_size i32)
51    (set_local $size (call $getCodeSize))
52
53    ;; copy entire thing into memory at offset 0
54    (call $codeCopy (i32.const 0) (i32.const 0) (get_local $size))
55
56    ;; retrieve payload size (the last 4 bytes treated as a little endian 32 bit number)
57    (set_local $payload_size (i32.load (i32.sub (get_local $size) (i32.const 4))))
58
59    ;; start offset is calculated as $size - 4 - $payload_size
60    (set_local $payload_offset (i32.sub (i32.sub (get_local $size) (i32.const 4)) (get_local $payload_size)))
61
62    ;; return the payload
63    (call $finish (get_local $payload_offset) (get_local $payload_size))
64  )
65)
66*/
67fn 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
80/// Returns a module which contains the deployable bytecode as a custom section.
81fn create_custom_deployer(payload: &[u8]) -> Result<Module, ModuleError> {
82    // The standard deployer code, which expects a 32 bit little endian as the trailing content
83    // immediately following the payload, placed in a custom section.
84    let code = deployer_code();
85
86    // This is the pre-written deployer code.
87    let mut module = Module::from_bytes(&code)?;
88
89    // Re-write memory to pre-allocate enough for code size
90    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        // This would be an internal error (.e.g the the deployer code above has no memory section)
95        .expect("failed to get memory section")
96        .entries_mut()[0] = mem_type;
97
98    // Prepare payload (append length).
99    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    // Prepare and append custom section.
105    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/// Returns a module which contains the deployable bytecode as a data segment.
115#[rustfmt::skip]
116fn create_memory_deployer(payload: &[u8]) -> Module {
117    // Instructions calling finish(0, payload_len)
118    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        // Create a func/type for the ethereum::finish
129        .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        // Create the "main fucntion"
142        .function()
143            // Empty signature `(func)`
144            .signature().build()
145            .body()
146              .with_instructions(parity_wasm::elements::Instructions::new(instructions))
147              .build()
148            .build()
149        // Export the "main" function.
150        .export()
151            .field("main")
152            .internal()
153              .func(2)
154            .build()
155        // Add default memory section
156        .memory()
157            .with_min(memory_initial)
158            .build()
159        // Export memory
160        .export()
161            .field("memory")
162            .internal()
163              .memory(0)
164            .build()
165        // Add data section with payload
166        .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}