Forráskód Böngészése

Implement msg.data

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 5 éve
szülő
commit
48f4bffb9a

+ 17 - 0
src/emit/ewasm.rs

@@ -139,6 +139,11 @@ impl EwasmTarget {
             .left()
             .unwrap();
 
+        contract.builder.build_store(
+            contract.calldata_len.as_pointer_value(),
+            args_length.into_int_value(),
+        );
+
         let args = contract
             .builder
             .build_call(
@@ -151,6 +156,10 @@ impl EwasmTarget {
             .unwrap()
             .into_pointer_value();
 
+        contract
+            .builder
+            .build_store(contract.calldata_data.as_pointer_value(), args);
+
         contract.builder.build_call(
             contract.module.get_function("callDataCopy").unwrap(),
             &[
@@ -211,6 +220,10 @@ impl EwasmTarget {
             "",
         );
 
+        contract
+            .builder
+            .build_store(contract.calldata_len.as_pointer_value(), args_length);
+
         let args = contract
             .builder
             .build_call(
@@ -223,6 +236,10 @@ impl EwasmTarget {
             .unwrap()
             .into_pointer_value();
 
+        contract
+            .builder
+            .build_store(contract.calldata_data.as_pointer_value(), args);
+
         contract.builder.build_call(
             contract.module.get_function("codeCopy").unwrap(),
             &[args.into(), code_size.into(), args_length.into()],

+ 113 - 6
src/emit/mod.rs

@@ -254,6 +254,8 @@ pub struct Contract<'a> {
     opt: OptimizationLevel,
     code_size: RefCell<Option<IntValue<'a>>>,
     selector: GlobalValue<'a>,
+    calldata_data: GlobalValue<'a>,
+    calldata_len: GlobalValue<'a>,
 }
 
 impl<'a> Contract<'a> {
@@ -417,6 +419,27 @@ impl<'a> Contract<'a> {
         selector.set_linkage(Linkage::Internal);
         selector.set_initializer(&context.i32_type().const_zero());
 
+        let calldata_len = module.add_global(
+            context.i32_type(),
+            Some(AddressSpace::Generic),
+            "calldata_len",
+        );
+        calldata_len.set_linkage(Linkage::Internal);
+        calldata_len.set_initializer(&context.i32_type().const_zero());
+
+        let calldata_data = module.add_global(
+            context.i8_type().ptr_type(AddressSpace::Generic),
+            Some(AddressSpace::Generic),
+            "calldata_data",
+        );
+        calldata_data.set_linkage(Linkage::Internal);
+        calldata_data.set_initializer(
+            &context
+                .i8_type()
+                .ptr_type(AddressSpace::Generic)
+                .const_zero(),
+        );
+
         Contract {
             name: contract.name.to_owned(),
             module,
@@ -433,6 +456,8 @@ impl<'a> Contract<'a> {
             opt,
             code_size: RefCell::new(None),
             selector,
+            calldata_data,
+            calldata_len,
         }
     }
 
@@ -742,9 +767,53 @@ impl<'a> Contract<'a> {
         runtime: &dyn TargetRuntime,
     ) -> BasicValueEnum<'a> {
         match e {
-            Expression::Builtin(_, _, Builtin::Signature, _) => self
+            Expression::Builtin(_, _, Builtin::Calldata, _) => self
                 .builder
-                .build_load(self.selector.as_pointer_value(), "selector"),
+                .build_call(
+                    self.module.get_function("vector_new").unwrap(),
+                    &[
+                        self.builder
+                            .build_load(self.calldata_len.as_pointer_value(), "calldata_len"),
+                        self.context.i32_type().const_int(1, false).into(),
+                        self.builder
+                            .build_load(self.calldata_data.as_pointer_value(), "calldata_data"),
+                    ],
+                    "",
+                )
+                .try_as_basic_value()
+                .left()
+                .unwrap(),
+            Expression::Builtin(_, _, Builtin::Signature, _) => {
+                // need to byte-reverse selector
+                let selector = self
+                    .builder
+                    .build_alloca(self.context.i32_type(), "selector");
+
+                // byte order needs to be reversed. e.g. hex"11223344" should be 0x10 0x11 0x22 0x33 0x44
+                self.builder.build_call(
+                    self.module.get_function("__beNtoleN").unwrap(),
+                    &[
+                        self.builder
+                            .build_pointer_cast(
+                                self.selector.as_pointer_value(),
+                                self.context.i8_type().ptr_type(AddressSpace::Generic),
+                                "",
+                            )
+                            .into(),
+                        self.builder
+                            .build_pointer_cast(
+                                selector,
+                                self.context.i8_type().ptr_type(AddressSpace::Generic),
+                                "",
+                            )
+                            .into(),
+                        self.context.i32_type().const_int(4, false).into(),
+                    ],
+                    "",
+                );
+
+                self.builder.build_load(selector, "selector")
+            }
             Expression::Builtin(_, _, _, _) => runtime.builtin(self, e, vartab, function, runtime),
             Expression::FunctionArg(_, _, pos) => function.get_nth_param(*pos as u32).unwrap(),
             Expression::BoolLiteral(_, val) => self
@@ -1567,9 +1636,27 @@ impl<'a> Contract<'a> {
             }
             Expression::ArrayLiteral(_, ty, dims, exprs) => {
                 // non-const array literals should alloca'ed and each element assigned
-                let array = self
+                let ty = self.llvm_type(ty);
+
+                let p = self
                     .builder
-                    .build_alloca(self.llvm_type(ty), "array_literal");
+                    .build_call(
+                        self.module.get_function("__malloc").unwrap(),
+                        &[ty.size_of()
+                            .unwrap()
+                            .const_cast(self.context.i32_type(), false)
+                            .into()],
+                        "array_literal",
+                    )
+                    .try_as_basic_value()
+                    .left()
+                    .unwrap();
+
+                let array = self.builder.build_pointer_cast(
+                    p.into_pointer_value(),
+                    ty.ptr_type(AddressSpace::Generic),
+                    "array_literal",
+                );
 
                 for (i, expr) in exprs.iter().enumerate() {
                     let mut ind = vec![self.context.i32_type().const_zero()];
@@ -1596,7 +1683,7 @@ impl<'a> Contract<'a> {
             Expression::AllocDynamicArray(_, ty, size, init) => {
                 let elem = match ty {
                     ast::Type::String | ast::Type::DynamicBytes => ast::Type::Bytes(1),
-                    _ => ty.array_deref(),
+                    _ => ty.array_elem(),
                 };
 
                 let size = self
@@ -2554,10 +2641,30 @@ impl<'a> Contract<'a> {
         for v in &cfg.vars {
             match v.storage {
                 cfg::Storage::Local if v.ty.is_reference_type() && !v.ty.is_contract_storage() => {
+                    let ty = self.llvm_type(&v.ty);
+
+                    let p = self
+                        .builder
+                        .build_call(
+                            self.module.get_function("__malloc").unwrap(),
+                            &[ty.size_of()
+                                .unwrap()
+                                .const_cast(self.context.i32_type(), false)
+                                .into()],
+                            &v.id.name,
+                        )
+                        .try_as_basic_value()
+                        .left()
+                        .unwrap();
+
                     vars.push(Variable {
                         value: self
                             .builder
-                            .build_alloca(self.llvm_type(&v.ty), &v.id.name)
+                            .build_pointer_cast(
+                                p.into_pointer_value(),
+                                ty.ptr_type(AddressSpace::Generic),
+                                &v.id.name,
+                            )
                             .into(),
                     });
                 }

+ 20 - 11
src/emit/substrate.rs

@@ -101,6 +101,11 @@ impl SubstrateTarget {
             .left()
             .unwrap();
 
+        contract.builder.build_store(
+            contract.calldata_len.as_pointer_value(),
+            args_length.into_int_value(),
+        );
+
         let args = contract
             .builder
             .build_call(
@@ -113,6 +118,10 @@ impl SubstrateTarget {
             .unwrap()
             .into_pointer_value();
 
+        contract
+            .builder
+            .build_store(contract.calldata_data.as_pointer_value(), args);
+
         contract.builder.build_call(
             contract.module.get_function("ext_scratch_read").unwrap(),
             &[
@@ -1387,18 +1396,18 @@ impl SubstrateTarget {
                         array_length,
                         &mut encoded_length,
                         |index, sum| {
-                            let index = contract.builder.build_int_mul(
-                                index,
-                                llvm_elem_ty
-                                    .into_pointer_type()
-                                    .get_element_type()
-                                    .size_of()
-                                    .unwrap()
-                                    .const_cast(contract.context.i32_type(), false),
-                                "",
-                            );
-
                             let elem = if dynamic_array {
+                                let index = contract.builder.build_int_mul(
+                                    index,
+                                    llvm_elem_ty
+                                        .into_pointer_type()
+                                        .get_element_type()
+                                        .size_of()
+                                        .unwrap()
+                                        .const_cast(contract.context.i32_type(), false),
+                                    "",
+                                );
+
                                 let p = unsafe {
                                     contract.builder.build_gep(
                                         arg.into_pointer_value(),

BIN
stdlib/stdlib.bc


+ 4 - 4
stdlib/stdlib.c

@@ -89,7 +89,7 @@ struct chunk
 {
 	struct chunk *next, *prev;
 	size_t length;
-	bool allocated;
+	size_t allocated;
 };
 
 void __init_heap()
@@ -407,14 +407,14 @@ struct vector *vector_new(uint32_t members, uint32_t size, uint8_t *initial)
 		do
 		{
 			*data++ = *initial++;
-		} while (size_array--);
+		} while (--size_array);
 	}
 	else
 	{
-		do
+		while (size_array--)
 		{
 			*data++ = 0;
-		} while (size_array--);
+		}
 	}
 
 	return v;

+ 1 - 0
tests/substrate_arrays/mod.rs

@@ -1584,6 +1584,7 @@ fn abi_encode_dynamic_array4() {
 
     runtime.constructor(0, Vec::new());
     runtime.function("test", Vec::new());
+    runtime.heap_verify();
 
     assert_eq!(
         runtime.vm.scratch,

+ 29 - 0
tests/substrate_builtins/mod.rs

@@ -1,3 +1,6 @@
+use parity_scale_codec::Encode;
+use parity_scale_codec_derive::{Decode, Encode};
+
 use super::{build_solidity, first_error};
 use solang::{parse_and_resolve, Target};
 
@@ -814,3 +817,29 @@ fn functions() {
 
     runtime.function("test", Vec::new());
 }
+
+#[test]
+fn data() {
+    #[derive(Debug, PartialEq, Encode, Decode)]
+    struct Uint32(u32);
+    #[derive(Debug, PartialEq, Encode, Decode)]
+    struct String(Vec<u8>);
+
+    let mut runtime = build_solidity(
+        r##"
+        contract bar {
+            constructor(string memory s) public {
+                assert(msg.data == hex"88eaeb6c18666f6f626172");
+                assert(msg.sig == hex"88ea_eb6c");
+            }
+
+            function test(uint32 x) public {
+                assert(msg.data == hex"e3cff634addeadde");
+                assert(msg.sig == hex"e3cf_f634");
+            }
+        }"##,
+    );
+
+    runtime.constructor(0, String(b"foobar".to_vec()).encode());
+    runtime.function("test", Uint32(0xdeaddead).encode());
+}